MyBatis使用总结
一、 简介:
MyBatis 是一个简化和实现了 Java 数据持久化层(persistence layer)的开源框架,它抽象了大量的 JDBC 冗余代码,并提供了一个简单易用的 API 和数据库交互。
在 Java 应用程序中,数据持久化层涉及到的工作有:将从数据库查询到的数据生成所需要的 Java 对象;将 Java 对象中的数据通过 SQL 持久化到数据库中。MyBatis 通过抽象底层的 JDBC 代码,自动化 SQL 结果集产生 Java 对象、 Java 对象的数据持久化数据库中的过程使得对 SQL 的使用变得容易。
二、 基本使用:
1、 定义SQL Mapper映射配置文件:
<select id="findStudentById" parameterType="int" resultType="Student"> SELECT STUD_ID AS studId, NAME, EMAIL FROM STUDENTS WHERE STUD_ID=#{Id} </select> <insert id="insertStudent" parameterType="Student"> INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL) VALUES(#{studId},#{name},#{email}) </insert>
2、 创建接口:
public interface StudentMapper { Student findStudentById(Integer id); void insertStudent(Student student); }
3、 创建配置文件:
创建 MyBatis 的主要配置文件 mybatis-config.xml,其中包括数据库连接信息,类型别名等等,然后将其加到 classpath 中;
<?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> <typeAliases> <typeAlias alias="Student" type="com.mybatis3.domain.Student" /> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="admin" /> </dataSource> /environment> </environments> <mappers> <mapper resource="com/mybatis3/mappers/StudentMapper.xml" /> </mappers> </configuration>
4、 新建MyBatisSqlSessionFactory类:
SqlSessionFactory会话工厂,生产SqlSession会话,使用时建议使用单例模式。Sqlsession会话,SqlSession是一个接口,此接口面向用户的,用户使用接口可以操作数据(增、删、改、查),SqlSession存在多线程访问,由SqlSession不是线程安全,SqlSession使用范围建议在方法中使用。
public class MyBatisSqlSessionFactory { private static SqlSessionFactory sqlSessionFactory; public static SqlSessionFactory getSqlSessionFactory() { if(sqlSessionFactory == null) { try { InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { throw new RuntimeException(e.getCause()); } } return sqlSessionFactory; } public static SqlSession openSession() { return getSqlSessionFactory().openSession(); } }
5、 定义POJO类:
public class Student { private Integer studId; private String name; private String email; private Date dob; }
6、 操作数据库:
SqlSession sqlSession = MyBatisSqlSessionFactory.openSession(); StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); return studentMapper.findAllStudents();
三、 MyBatis缓存:
一级缓存:
MyBatis 对通过映射的SELECT语句加载的查询结果提供了内建的缓存支持。默认情况下,启用一级缓存;即,如果你使用同一个 SqlSession接口对象调用了相同的 SELECT 语句,则直接会从缓存中返回结果,而不是再查询一次数据库。
二级缓存:
在 SQL 映射器 XML 配置文件中使用<cache />元素添加全局二级缓存。 此时所有的在映射语句文件定义的<select>语句的查询结果都会被缓存,所有的在映射语句文件定义的<insert>,<update> 和<delete>语句将会刷新缓存。
通过复写默认属性来自定义缓存的行为,如下:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
可以为任意特定的映射语句复写默认的 cache 行为;例如,对一个 select 语句不使用缓存,可以设置useCache=“false”;如下:
<select ... flushCache="false" useCache="true"/> <insert ... flushCache="true"/> <update ... flushCache="true"/> <delete ... flushCache="true"/>
四、 ResultMap:
ResultMaps 被用来 将 SQL SELECT 语句的结果集映射到 JavaBeans的属性中。我们可以定义结果集映射 ResultMaps并且在一些 SELECT 语句上引用 resultMap。
1、 基本ResultMap:
使用例子如下:
<resultMap id="StudentResult" type="com.mybatis3.domain.Student"> <id property="studId" column="stud_id" /> <result property="name" column="name" /> <result property="email" column="email" /> <result property="phone" column="phone" /> </resultMap> <select id="findAllStudents" resultMap="StudentResult"> SELECT * FROM STUDENTS </select> <select id="findStudentById" parameterType="int" resultMap="StudentResult"> SELECT * FROM STUDENTS WHERE STUD_ID=#{studId} </select>
2、 Map类型ResultMap:
<select id="findStudentById" parameterType="int" resultType="map"> SELECT * FROM STUDENTS WHERE STUD_ID=#{studId} </select>
在上述的<select>语句中,我们将 resultType 配置成 map,即 java.util.HashMap 的别名。在这种情况下,结果集的列名将会作为 Map 中的 key 值,而列值将作为 Map 的 value 值。
3、 扩展ResultMap:
ResultMap可以继承,如:
<resultMap type="Student" id="StudentResult"> <id property="studId" column="stud_id" /> <result property="name" column="name" /> <result property="email" column="email" /> <result property="phone" column="phone" /> </resultMap> <resultMap type="Student" id="StudentWithAddressResult" extends="StudentResult"> <result property="address.addrId" column="addr_id" /> <result property="address.street" column="street" /> <result property="address.city" column="city" /> <result property="address.state" column="state" /> <result property="address.zip" column="zip" /> <result property="address.country" column="country" /> </resultMap>
ResultMap还可以嵌套,如:
<resultMap type="Address" id="AddressResult"> <id property="addrId" column="addr_id" /> <result property="street" column="street" /> <result property="city" column="city" /> <result property="state" column="state" /> <result property="zip" column="zip" /> <result property="country" column="country" /> </resultMap> <resultMap type="Student" id="StudentWithAddressResult"> <id property="studId" column="stud_id" /> <result property="name" column="name" /> <result property="email" column="email" /> <association property="address" resultMap="AddressResult" /> </resultMap>
也可以使用<association 定义内联的 resultMap,如:
<resultMap type="Student" id="StudentWithAddressResult"> <id property="studId" column="stud_id" /> <result property="name" column="name" /> <result property="email" column="email" /> <association property="address" javaType="Address"> <id property="addrId" column="addr_id" /> <result property="street" column="street" /> <result property="city" column="city" /> <result property="state" column="state" /> <result property="zip" column="zip" /> <result property="country" column="country" /> </association> </resultMap>
五、 动态SQL:
1. IF条件:
<if>元素被用来有条件地嵌入 SQL 片段,如果测试条件被赋值为 true,则相应地 SQL 片段将会被添加到 SQL 语句中。 如下:
<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"></select> SELECT * FROM COURSES WHERE TUTOR_ID= #{tutorId} <if test="courseName != null"> AND NAME LIKE #{courseName} </if> <if test="startDate != null"> AND START_DATE >= #{startDate} </if> <if test="endDate != null"> AND END_DATE <= #{endDate} </if> </select>
2. Choose、when、otherwise条件:
<choose>条件可以根据查询条件生成不同的SQL查询语句,如下:
<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"> SELECT * FROM COURSES <choose> <when test="searchBy == 'Tutor'"> WHERE TUTOR_ID= #{tutorId} </when> <when test="searchBy == 'CourseName'"> WHERE name like #{courseName} </when> <otherwise> WHERE TUTOR start_date >= now() </otherwise> </choose> </select>
3. Where条件:
在需要使用至少一种查询条件的情况下, 我们应该使用WHERE子句。并且, 如果有多个条件,我们需要在条件中添加 AND 或 OR。MyBatis 提供了<where>元素支持这种类型的动态SQL语句。 如下:
<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"> SELECT * FROM COURSES <where> <if test=" tutorId != null "> TUTOR_ID= #{tutorId} </if> <if test="courseName != null"> AND name like #{courseName} </if> <if test="startDate != null"> AND start_date >= #{startDate} </if> <if test="endDate != null"> AND end_date <= #{endDate} </if> </where> </select>
<where>元素只有在其内部标签有返回内容时才会在动态语句上插入 WHERE 条件语句。并且,如果 WHERE 子句以AND或者 OR打头,则打头的AND 或OR将会被移除。
4. Trim条件:
<trim>元素和<where>元素类似,但是<trim>提供了在添加前缀/后缀 或者 移除前缀/后缀方面提供更大的灵活性。
<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"> SELECT * FROM COURSES <trim prefix="WHERE" prefixOverrides="AND | OR"> <if test=" tutorId != null "> TUTOR_ID= #{tutorId} </if> <if test="courseName != null"> AND name like #{courseName} </if> </trim> </select>
这里如果任意一个<if>条件为true,<trim>元素会插入 WHERE,并且移除紧跟WHERE 后面的AND 或 OR 。
5. Foreach循环:
<foreach>条件可以迭代遍历一个数组或者列表,构造AND/OR条件或
一个IN子句。
<select id="searchCoursesByTutors" parameterType="map" resultMap="CourseResult"> SELECT * FROM COURSES <if test="tutorIds != null"> <where> <foreach item="tutorId" collection="tutorIds"> OR tutor_id=#{tutorId} </foreach> </where> </if> </select>
<select id="searchCoursesByTutors" parameterType="map" resultMap="CourseResult"> SELECT * FROM COURSES <if test="tutorIds != null"> <where> tutor_id IN <foreach item="tutorId" collection="tutorIds" open="(" separator="," close=")"> #{tutorId} </foreach> </where> </if> </select>
6. Set条件:
<set>元素和<where>元素类似,如果其内部条件判断有任何内容返回时,他会插入SET SQL片段。 如下:
<update id="updateStudent" parameterType="Student"> update students <set> <if test="name != null">name=#{name},</if> <if test="email != null">email=#{email},</if> <if test="phone != null">phone=#{phone},</if> </set> where stud_id=#{id} </update>
六、 Spring中集成MyBatis:
1. 配置MyBatis Beans:
在applicationContext.xml中配置让 Spring 来实例化 MyBatis 组件如 SqlSessionFactory、SqlSession、以及映射器 Mapper 对象:
<beans> <bean id="dataSource" class="org.springframework.jdbc.datasource. DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/elearning" /> <property name="username" value="root" /> <property name="password" value="admin" /> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="typeAliases" value="com.mybatis3.domain.Student, com.mybatis3.domain.Tutor" /> <property name="typeAliasesPackage" value="com.mybatis3.domain" /> <property name="typeHandlers" value="com.mybatis3.typehandlers.PhoneTypeHandler" /> <property name="typeHandlersPackage" value="com.mybatis3.typehandlers" /> <property name="mapperLocations" value="classpath*:com/mybatis3/**/*.xml" /> <property name="configLocation" value="WEB-INF/mybatisconfig.xml" /> </bean> </beans>
2. Mapper Scan:
<mybatis:scan>元素将在特定的以逗号分隔的包名列表中搜索映射器 Mapper 接口。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd"> <mybatis:scan base-package="com.mybatis3.mappers" /> </beans>
3. 事务管理:
- 配置 TransactionManager bean 实体对象:
<bean id="transactionManager" class="org.springframework.jdbc. datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
- 在Spring中使用基于注解的事务管理特性:
<tx:annotation-driven transaction-manager="transactionManager"/>
- 使用事务:
可以在Spring service bean 上使用@Transactional 注解,表示在此service 中的每一个方法都应该在一个事务中运行。如果方法成功运行完毕,Spring 会提交操作。如果有运行期异常发生,则会执行回滚操作。
@Service @Transactional public class StudentService { @Autowired private StudentMapper studentMapper; public Student createStudent(Student student) { studentMapper.insertAddress(student.getAddress()); if(student.getName().equalsIgnoreCase("")) { throw new RuntimeException("Student name should not be empty."); } studentMapper.insertStudent(student); return student; } }