上篇SSM框架环境搭建篇,演示了咱们进行web开发必不可少的一些配置和准备工做,若是这方面还有疑问的地方,能够先参考上一篇“SSM框架开发web项目系列(一) 环境搭建篇”。本文主要介绍MyBatis的基础内容,包括基本概念、开发步骤、使用实例等。提及MyBatis,工做中作过SSH/SSM相关Web开发的或者正在学习MyBatis的人或多或少都会接触到相似“MyBatis和Hibernate有什么区别?”,“MyBatis和Hibernate哪一个更好?”,“为何Mybatis用的人愈来愈多?”等等...记得面试问题,区别问的最多,有次被面试官问到更喜欢用哪个?明明已经知道这个公司介绍用的是SSM了,我答了个Hibernate,并说先用的也是Hibernate,或许初恋的感受过于深入吧...谁好谁差这种主观性问题,咱们不争论,可是不容质疑的是二者都为企业级开发作出巨大贡献。同时,带着问题和求知欲去学习每每会让学习效率大大提升,由于许多问题在困惑你的同时,也为你指引了方向。就正如你得会用它,理解它了,才知道它在某方面为何会不足。html
早些时候,Apache有一个开源项目iBatis,后来更名了叫Mybatis,因此咱们在网上有时候会看到一些早期的文章有时候看到iBatis,实际上是同一个东西。同时,你们能够看下MyBatis源码工程结构,以下图,也能发现这个问题。java
MyBatis是一个半自动-ORM-持久层框架,下面分别介绍这三个概念,若是了解的的能够直接跳过以节省时间。mysql
首先持久层比较好理解,就是针对数据库的各类操做持久化层面,咱们用jdbc也能够对数据库中表进行增删可查;WEB开发分层结构中,相似的还有业务层、控制层,MyBatis所作用的层,主要是用于与数据库打交道。web
其次ORM(Object Relational Mapping,对象关系映射)是一种技术,也是思想,若是用过jdbc的原生方式操做数据的应该都知道,其中各类获取和更新的操做都已有相关的API了,可是这个过程实在太繁琐,获取链接、构造语句、发送SQL和接收数据、最后是处理数据和关闭流等等...实际的工做开发中,显然不太适用。也许是有人想到,最麻烦的地方在于获取数据后的处理过程,为了简化这一过程,以Java中面向对象的思惟构造了这一个ORM关系模型,即每张数据表对应一个Java类,数据表中每一条记录分别对应Java类的一个实体对象,数据表中每一个字段对应Java类中的一个属性,这样一来Java中一切皆对象,数据库里的东西既然已经对应映射到Java概念中来,咱们再用面向对象的思惟去操做数据库,就大大简化了开发流程。面试
最后,解释半自动,既然有半自动,应该就有全自动,例如Hibernate就是一个全自动的ORM持久层框架,它在创建数据库和bean对象关系映射模型的同时,提供的api还会帮助咱们自动生成和发送SQL语句去操做数据库,而MyBatis略有不一样,它也创建了对象关系映射模型,可是并不会帮助咱们生成SQL语句,须要咱们本身写SQL语句,很多人可能会以为别人均可以帮你自动生成了这还要本身写,不是没事找事吗?可是偏偏相反,不少人由于这点喜欢上了MyBatis,灵活且透明,本身动手不解释。sql
关于MyBatis的学习使用过程当中,依次要注意的四个对象有SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper实例。数据库
1.SqlSessionFactoryBuilderapache
SqlSessionFactoryBuilder是一个类,里面定义许多重载的build方法,经过build方法能够获取SqlSessionFactory对象,即SqlSession工厂实例api
2.SqlSessionFactorysession
SqlSessionFactory是一个接口,看名字应该能明白是SqlSession工厂,里面定义了许多重载的openSession方法,用于获取SqlSession对象
3.SqlSession
SqlSession是一个很关键的接口,经过它咱们能够执行发送SQL语句、得到Mapper实例等等。以它的第一个方法为例, <T> T selectOne(String statement); 方法名很容易理解,获取数据表的一条记录(在Java中对应返回一个实体类对象),前面的泛型对应的就是实体类的类型,关于String类型的参数statement,用过原生的JDBC操做数据库的应该不会陌生,在使用JDBC过程当中,有个Statement对象,经过该对象的相似 ResultSet executeQuery(String sql) throws SQLException; 等方法能够发送SQL语句,方法里的字符串类型参数 sql 就是咱们要发送的sql语句,而前面的String statement 一样也是表明咱们的sql语句。总的来讲,selectOne中的statement表明sql语句,JDBC中的statement是能发送sql语句的对象实例,不可混淆。
4.Mapper实例
Mapper实例就是咱们在dao层定义的定义的接口实例,咱们在service层中注入dao对象时关联的是该接口名,而实际上咱们拿到了该接口实例也就是Mapper实例。而咱们在web开发过程当中,持久层的相关方法都定义在Mapper接口中,因此四个对象里咱们在前面环境搭建篇比较容易发现的也就是这个Mapper实例所属接口,即PersonMappr接口。Mapper实例能够经过SqlSession的getMapper方法得到。
以上为MyBatis配置文件下节点的结构分布图,熟悉DTD的根据org/apache/ibatis/builder/xml下的约束文件mybatis-*-config.dtd也能够获取XML规范。
environment(环境)
在开发中,咱们要链接到数据库,每每都须要配置一个数据源,其中包括数据库url参数,用户名和密码等等,另外还有事事务管理器配置。MyBatis中也不例外,在这里针对一个数据库的链接,有一个environment(环境)与之对应,若是有多个数据库,咱们能够在environments下定义多个environment。environment下面经过dataSource和transactionManager的property属性进行数据源和事务管理器配置。
typeAliases(类型命名)
这个是开发中很实用的配置,前面配置篇中mybatis-config.xml中的<typeAlias alias="person" type="com.mmm.pojo.Person" />,给类绑定别名,而后在其余地方引用时能够不用写类的全名(相似com.xxx.Xxx形式),直接写别名便可,例如后面personMapper.xml映射文件中<resultMap type="person" id="personResultMap" >,这里的person别名就表明该类了,若是没有前面的别名绑定,咱们在全部须要类型type指定com.mmm.pojo.Person的时候,都须要写全名。另外MyBatis中自己已经绑定了许多相似的别名,在Configuration类的构造中已经预先注册绑定了相关别名,这也是咱们在用Spring集成开发的配置文件中那些特殊别名能获得解析的关键所在,以下所示
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class); typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class); typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class); typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class); typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class); typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class); typeAliasRegistry.registerAlias("FIFO", FifoCache.class); typeAliasRegistry.registerAlias("LRU", LruCache.class); typeAliasRegistry.registerAlias("SOFT", SoftCache.class); typeAliasRegistry.registerAlias("WEAK", WeakCache.class); typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class); typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class); typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class); typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class); typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class); typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class); typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class); typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class); typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class); typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class); typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class); typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class); languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class); languageRegistry.register(RawLanguageDriver.class); }
mappers(映射器)
<mappers> <mapper resource="com/xxx/xxx/mapper/xxxMapper.xml" /> </mappers>
以上即为一个映射器配置样式,经过该配置,Mybatis会找到相应的SQL映射文件(前面环境搭建篇中为personMapper.xml),下面详细介绍SQL映射文件。
The true power of MyBatis is in the Mapped Statements(MyBatis真正的力量就在SQL映射语句里)。这是MyBatis对SQL映射文件做介绍的第一句话,足以体现其重要性,前面说到的半自动的MyBatis须要本身写SQL语句,这个写SQL语句的地方就在这里。
根节点mapper有一个属性namespace(命名空间),对应的是Mapper接口的全名,经过这个属性值的设置,MyBatis才能找到该SQL映射文件对象Mapper接口,从而构造相应的Mapper实例对象。
以上为MyBatis的SQL映射xml文件的元素结构,子节点中还有一个parameterMap,不过已经被废弃了,就没画上去。前面四个,看单词意思,应该不难理解,分别用于定义增删改查SQL语句。下面以查询<select>为例
<!-- 根据主键id查找记录 --> <select id="selectById" resultType="person"> select * from `TBL_PERSON` where id = #{id} </select>
上面select节点中id为该节点的惟一标识,与其它节点区分,另外一方面,id名对应咱们的Mapper接口中的方法名,在这里对应PersonMapper的以下方法:
//根据主键id查找Person对象 Person selectById(String id);
因为是查询,会有返回数据内容,基于ORM思想,这里的T_PERSON表返回记录有一个实体类与之对应,那么具体对应哪一个实体类怎么指定?这里的resultType即指定返回数据对应类型,而且用到了别名,因此这里其实就是指定了com.mmm.pojo.Person类做为对应实体类。另外还有一种resultMap定义方式,也能够指定返回类型,二者不能同时使用,下面会具体讲到。若是方法没有返回值,也能够不指定类型。
节点中的语句即为该方法对应的SQL语句,这里的#{id}表示参数,对应PersonMapper接口中对应方法的参数String id。
另外三种<delete><updata><insert>相似,不过要注意,<insert>做为插入节点,有几个特殊属性,useGeneratedKeys、keyProperty、keyColumn,这三个属性都是<insert>特有的,也仅对其有效,keyProperty属性指定数据表主键值对应的实体类属性,这里为Person类中的id;keyColumn属性指定数据表主键字段名,这里为id;useGeneratedKeys指定是否使用数据表主键策略生成的主键值,例如在Mysql中主键能够设置自增,而后咱们在插入记录(或者说是写SQL语句)时,即便不指定主键值,插入也会成功,而且主键会自动赋值。为了以示区别,文中构建示例我会使用MySQL的自增主键,而不是以前的随机字符串做为主键。
<sql>被用来定义可重用的SQL代码段,能够包含在其余语句中。
再来看<resultMap>,以前的Person实例中,数据表的字段名和实体类属性名都是同样的,id,name,gender。若是不同的话,咱们再采用以前的写法就会有问题了,resultMap给咱们提供了解决办法,下面咱们经过完整构建一个Mybatis环境来演示总体内容。
这里咱们单独讲Mybatis,并未使用Spring集成环境,也并未用到web层的Spring MVC,因此不须要构建web项目。因此首先经过maven新建一个java项目,pom.xml依赖能够参考前面的SSM环境搭建,最后项目结构大体以下图所示
数据库中准备一张员工表TBL_EMP,三个字段:主键id自增,姓名emp_name,性别emp_gender,插入若干数据,以下图
package com.mmm.pojo; //员工实体类 public class Emp { private Integer id; //主鍵 private String name; //员工姓名 private String gender; //员工性别 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 这里能够定义类的别名,在mapper.xml文件中应用会方便不少 --> <typeAliases> <typeAlias alias="emp" type="com.mmm.pojo.Emp" /> </typeAliases> <!-- 环境配置 --> <environments default="envir"> <environment id="envir"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/ssm?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/mmm/mapper/empMapper.xml"/> </mappers> </configuration>
package com.mmm.mapper; import java.util.List; import com.mmm.pojo.Emp; public interface EmpMapper { //新增一个Emp对象 void insert(Emp p); //根据主键id删除Emp对象 void deleteById(Integer id); //修改一个Emp对象 void update(Emp p); //根据主键id查找Emp对象 Emp selectById(Integer id); //查找全部Emp对象,返回集合类型 List<Emp> selectAll(); }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace命名空间绑定Mapper接口 --> <mapper namespace="com.mmm.mapper.EmpMapper"> <!-- resultMap定义,property对应实体类中属性,column对应数据表字段名 --> <resultMap type="emp" id="empResultMap" > <id property="id" column="id"></id> <result property="name" column="emp_name"></result> <result property="gender" column="emp_gender"></result> </resultMap> <!-- 新增一条记录,这里并未在SQL语句中设置主键id值 --> <insert id="insert" parameterType="emp" useGeneratedKeys="true" keyProperty="id" keyColumn="id" > insert into `TBL_EMP`(emp_name,emp_gender) values (#{name},#{gender}) </insert> <!-- 删除一条记录 --> <delete id="deleteById"> delete from `TBL_EMP` where id = #{id} </delete> <!-- 更新一条记录 --> <update id="update" parameterType="EMP"> update `TBL_EMP` set emp_name = #{name}, emp_gender = #{gender} </update> <!-- 查找全部记录 --> <select id="selectAll" resultMap="empResultMap"> select * from `TBL_EMP` </select> <!-- 根据主键id查找记录 --> <select id="selectById" resultMap="empResultMap"> select * from `TBL_EMP` where id = #{id} </select> </mapper>
package com.mmm.test; import java.io.IOException; import java.io.Reader; import java.util.List; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.mmm.mapper.EmpMapper; import com.mmm.pojo.Emp; public class TestMyBatis { @Test public void testCore() throws IOException { //直接实例SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //MyBatis配置文件路径 String path = "mybatis-config.xml"; //经过路径获取输入流 Reader reader = Resources.getResourceAsReader(path); //经过reader构建sessionFactory SqlSessionFactory sessionFactory = builder.build(reader); //获取SqlSession对象 SqlSession sqlSession = sessionFactory.openSession(); //获取Mapper实例 EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); //获取全部记录并遍历展现 List<Emp> list = mapper.selectAll(); for(Emp emp:list) { System.out.println("姓名:"+emp.getName()+",性别:"+emp.getGender()); } } }
运行程序成功,结果以下
本文主要介绍了单独以MyBatis构建数据库访问程序的方法步骤,涉及的都是MyBatis基础和核心的内容,数据库也是针对的单表操做。MyBatis的关联查询、动态SQL、事务管理和Spring集成MyBatis等内容准备梳理一番了以后写出来。