摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。
MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由Apache Software Foundation迁移到了Google Code,并且改名为MyBatis。
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs映射成数据库中的记录。
尽管我们接触更多的是MyBatis与Spring的整合使用,但是MyBatis有它自己的独立使用方法,了解其独立使用的方法套路对分析Spring整合MyBatis非常有帮助,因为Spring无非就是将这些功能进行封装以简化我们的开发流程。MyBatis独立使用包括以下几步。
(1)建立PO。
用于对数据库中数据的映射,是程序员更关注于对Java类的使用而不是数据库的操作。
public class User { private Long id; private String username; private Integer age; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username == null ? null : username.trim(); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
(2)建立Mapper。
数据库操作的映射文件,也就是我们常说的DAO,用于映射数据库的操作,也可以通过配置文件指定方法对应的SQL语句或者直接使用Java提供的注解方式进行SQL指定。
public interface UserMapper { int insert(User record); User selectByPrimaryKey(Long id); }
(3)建立配置文件。
配置文件主要用于配置程序中可变性高的配置,一个偏大的程序一定会存在一些经常会变化的变量,如果每次变化都需要改变源码那会是非常糟糕的设计,所以,我们看到各种各样的框架或者应用的时候都免不了要配置配置文件,MyBatis中的配置文件主要封装在configuration中,配置文件的基本结构如下图所示。
configuration | 根元素 |
properties | 定义配置外在化 |
settings | 一些全局性的配置 |
typeAliases | 为一些类定义别名 |
typeHandlers | 定义类型处理,也就是定义Java类型与数据库中的数据类型之间的转换关系 |
objectFactory | 用于指定结果集对象的实例是如何创建的 |
mappers | 指定映射文件或映射类 |
environments | 环境 |
environment | 配置MyBatis的环境 |
transactionManager | 事务管理器 |
dataSource | 数据源 |
plugins | MyBatis的插件,插件可以修改MyBatis内部的运行规则 |
读者如果对上面的各个配置具体使用方法感兴趣,可以进一步查阅相关资料,这里只举出最简单的实例以方便读者快速回顾MyBatis。
<?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> <!--属性--> <properties resource="properties/database.properties"/> <!--设置--> <settings> <setting name="cacheEnabled" value="false"/> <setting name="useGeneratedKeys" value="true"/> <setting name="defaultExecutorType" value="REUSE"/> </settings> <!--类型命名--> <typeAliases> <typeAlias alias="User" type="org.cellphone.uc.repo.po.User"/> </typeAliases> <!--配置环境--> <environments default="development"> <!--环境变量--> <environment id="development"> <!--事务管理器--> <transactionManager type="jdbc"/> <!--数据源--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!--映射器--> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers> </configuration>
(4)建立映射文件。
对应于MyBatis全局配置中的mappers配置属性,主要用于建立对应数据库操作接口的SQL映射。MyBatis会将这里设定的SQL与对应的Java接口相关联,以保证在MyBatis中调用接口的时候会到数据库中执行相应的SQL来简化开发。
<?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"> <mapper namespace="org.cellphone.uc.repo.mapper.UserMapper"> <resultMap id="BaseResultMap" type="org.cellphone.uc.repo.po.User"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. This element was generated on Sat Apr 21 15:38:35 CST 2018. --> <id column="id" jdbcType="BIGINT" property="id" /> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="age" jdbcType="INTEGER" property="age" /> </resultMap> <sql id="Base_Column_List"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. This element was generated on Sat Apr 21 15:38:35 CST 2018. --> id, username, age </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. This element was generated on Sat Apr 21 15:38:35 CST 2018. --> select <include refid="Base_Column_List" /> from user where id = #{id,jdbcType=BIGINT} </select> <insert id="insert" parameterType="org.cellphone.uc.repo.po.User"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. This element was generated on Sat Apr 21 15:38:35 CST 2018. --> insert into user (id, username, password, sex, age, status, create_tm ) values (#{id,jdbcType=BIGINT}, #{username,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER} ) </insert> </mapper>
(5)建立测试类。
至此我们已经完成了MyBatis的建立过程,接下来的工作就是对之前的所有工作进行测试,以便直接查看MyBatis为我们提供的结果。
public class MyBatisUtils { private final static SqlSessionFactory SQL_SESSION_FACTORY; static { String resource = "mybatis-config.xml"; Reader reader = null; try { reader = Resources.getResourceAsReader(resource); } catch (IOException e) { e.printStackTrace(); } SQL_SESSION_FACTORY = new SqlSessionFactoryBuilder().build(reader); } public static SqlSessionFactory getSqlSessionFactory() { return SQL_SESSION_FACTORY; } }
public class MapperTest { static SqlSessionFactory sqlSessionFactory = null; static { sqlSessionFactory = MyBatisUtils.getSqlSessionFactory(); } @Test public void testAdd() { SqlSession sqlSession = sqlSessionFactory.openSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setUsername("hello"); user.setAge(5); userMapper.insert(user); sqlSession.commit(); // 这里一定要提交,不然数据进不去数据库中 } finally { sqlSession.close(); } } @Test public void getUser() { SqlSession sqlSession = sqlSessionFactory.openSession(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.selectByPrimaryKey(32L); System.out.println("name: " + user.getUsername() + "| age: " + user.getAge()); } finally { } } }
注意,这里在数据库中设定了id自增策略,所以插入的数据会直接在数据库中赋值,当执行测试后如果数据表为空,那么在表中会出现一条我们插入的数据,并会在查询时将此数据查出。