属性(properties)
这些属性可以在外部进行配置,并可以进行动态替换。既可以在典型的java属性文件中配置这些属性,也可以在properties元素的子元素中设置。
我们可以使用properties加载一个资源文件,资源文件中可以配置各种属性。
在mybatis-config.xml配置文件中引用这个文件:
tips:如果在外部的properties中配置的属性和当前的配置文件
设置(settings)
这是MyBatis中极为重要的调整设置,它们会改变MyBatis的运行时行为。
<!-- 显示mybatis执行日志 -->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
类型别名(typeAliases)
类型别名可以为java类型设置一个缩写的名字。它仅用于xml配置,意在降低冗余的全限定类名书写。例如:
<typeAliases>
<!-- 配置一个别名 -->
<typeAlias alias="teacher" type="com.quail.pojo.Teacher"/>
<!-- 配置一个包,这个包下的所有的类都可以直接使用类的简称(不区分首字母大小写) -->
<package name="com.quail.pojo" />
</typeAliases>
类型处理器(typeHandlers)
MyBatis在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时,都会用类型处理器将获取到的值以合适的方式转换成java类型。
对象工厂(objectFactory)
每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现。
ObjectFactory 接口很简单,它包含两个创建实例用的方法,一个是处理默认无参构造方法的,另外一个是处理带参数的构造方法的。 另外,setProperties 方法可以被用来配置 ObjectFactory,在初始化你的 ObjectFactory 实例后, objectFactory 元素体中定义的属性会被传递给 setProperties 方法。
插件(plugins)
MyBatis允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
环境配置(environments)
MyBatis可以配置成适应多环境,这种机制有助于将SQL映射应用于多种数据库之中,现实情况下有多种理由需要这么做。例如,开发、测试和生成环境需要有不同的配置;或者想在具有相同Schema的多个生成数据库中使用相同的SQL映射。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。映射器(mappers)
用于定位sql映射语句的配置文件
<!-- 使用相对于类路径(classpath)的资源引用 --> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> </mappers> <!-- 使用完全限定资源定位符(URL) --> <mappers> <mapper url="file:///var/mappers/AuthorMapper.xml"/> </mappers> <!-- 使用映射器接口实现类的完全限定类名 --> <mappers> <mapper class="org.mybatis.builder.AuthorMapper"/> </mappers> <mappers> <!-- 最常用的方式 --> <package name="org.mybatis.builder"/> </mappers>
关系查询
一对一查询
<resultMap id="studentMapping" type="com.quail.pojo.Student"> <id column="stuId" property="stuId" javaType="java.lang.Long"/> <result column="stuName" property="stuName" /> <result column="loginPass" property="loginPass" /> <result column="stuGender" property="stuGender" /> <result column="stuAge" property="stuAge" /> <result column="stuBirth" property="stuBirth" /> <result column="stuTel" property="stuTel" /> <result column="stuEducation" property="stuEducation" /> <result column="status" property="status" /> <result column="classId" property="classId" /> <!-- 一对一关系映射,连接查询 --> <association column="classId" property="classInfo" javaType="com.quail.pojo.ClassInfo" > <id column="classId" property="classId" /> <result column="className" property="className" /> <result column="roomId" property="roomId" /> <result column="teacherId" property="teacherId" /> <result column="headmasterId" property="headmasterId" /> <result column="startTime" property="startTime" /> <result column="endTime" property="endTime" /> <result column="status" property="status" /> </association> </resultMap> <select id="queryStuById" parameterType="long" resultMap="studentMapping"> select st.*,c.className,c.roomId,c.teacherId,c.headmasterId,c.startTime,c.endTime,c.status from student st join classinfo c on st.classId = c.classId where st.stuId = #{stuId} </select> <resultMap id="studentMapping2" type="com.quail.pojo.Student"> <id column="stuId" property="stuId" javaType="java.lang.Long"/> <result column="stuName" property="stuName" /> <result column="loginPass" property="loginPass" /> <result column="stuGender" property="stuGender" /> <result column="stuAge" property="stuAge" /> <result column="stuBirth" property="stuBirth" /> <result column="stuTel" property="stuTel" /> <result column="stuEducation" property="stuEducation" /> <result column="status" property="status" /> <result column="classId" property="classId" /> <!-- 一对一关系映射,子查询 --> <association column="classId" property="classInfo" select="queryByClassId" javaType="com.quail.pojo.ClassInfo" > <id column="classId" property="classId" /> <result column="className" property="className" /> <result column="roomId" property="roomId" /> <result column="teacherId" property="teacherId" /> <result column="headmasterId" property="headmasterId" /> <result column="startTime" property="startTime" /> <result column="endTime" property="endTime" /> <result column="status" property="status" /> </association> </resultMap> <select id="queryByStudentId" parameterType="long" resultMap="studentMapping2"> select * from student where stuId = #{stuId} </select> <select id="queryByClassId" parameterType="long" resultType="classInfo"> select * from classInfo where classId = #{classId} </select>
测试:
@Test public void testStuIdByClassId(){ Student student = sqlSession.selectOne("com.quail.dao.StudentDao.queryStuById",3l); System.out.println(student); } @Test public void testStuIdByClassId2(){ Student student = sqlSession.selectOne("com.quail.dao.StudentDao.queryByStudentId",3l); System.out.println(student); }
一对多查询
<!-- 一对多关系映射 --> <resultMap id="classAndStudentResMapping" type="classInfo"> <id column="classId" property="classId" /> <result column="className" property="className" /> <result column="roomId" property="roomId" /> <result column="teacherId" property="teacherId" /> <result column="headmasterId" property="headmasterId" /> <result column="startTime" property="startTime" /> <result column="endTime" property="endTime" /> <result column="status" property="status" /> <!-- 配置一对多的关系映射 --> <!-- property:属性名 javaType:集合类型 ofType:集合中的类型 --> <collection property="students" column="ClassId" javaType="java.util.List" ofType="Student"> <id column="stuId" property="stuId" javaType="java.lang.Long"/> <result column="stuName" property="stuName" /> <result column="loginPass" property="loginPass" /> <result column="stuGender" property="stuGender" /> <result column="stuAge" property="stuAge" /> <result column="stuBirth" property="stuBirth" /> <result column="stuTel" property="stuTel" /> <result column="stuEducation" property="stuEducation" /> <result column="status" property="status" /> <result column="classId" property="classId" /> </collection> </resultMap> <select id="queryClassAndStuByCid" parameterType="long" resultMap="classAndStudentResMapping"> select st.*,c.* from student st join classInfo c on st.classId = c.classId where c.classId=#{classId} </select> <!-- 一对多关系,子查询 --> <resultMap id="classAndStudentResMapping2" type="classInfo"> <id column="classId" property="classId" /> <result column="className" property="className" /> <result column="roomId" property="roomId" /> <result column="teacherId" property="teacherId" /> <result column="headmasterId" property="headmasterId" /> <result column="startTime" property="startTime" /> <result column="endTime" property="endTime" /> <result column="status" property="status" /> <!-- 配置一对多的关系映射 --> <!-- property:属性名 javaType:集合类型 ofType:集合中的类型 --> <collection property="students" column="classId" select="studentByIdQuery3" javaType="java.util.List" ofType="Student"/> </resultMap> <select id="studentByIdQuery3" parameterType="long" resultType="com.quail.pojo.Student"> select * from student where classId = #{classId} </select> <select id="classByIdQuery2" parameterType="long" resultMap="classAndStudentResMapping2"> select * from classInfo where classId = #{classId} </select>
测试:
@Test public void testClassAndStuQuery(){ ClassInfo classInfo = sqlSession.selectOne("com.quail.dao.StudentDao.queryClassAndStuByCid", 1l); System.out.println(classInfo); for (Student student : classInfo.getStudents()) { System.out.println(student); } } @Test public void testClassAndStuQuery2(){ ClassInfo classInfo = sqlSession.selectOne("com.quail.dao.StudentDao.classByIdQuery2", 1l); System.out.println(classInfo); for (Student student : classInfo.getStudents()) { System.out.println(student); } }
延迟加载
当开启延迟加载时,所有关联对象都会延迟加载。每个延迟加载属性会按需加载。
<settings> <!-- 显示mybaits执行日志 --> <setting name="logImpl" value="STDOUT_LOGGING"/> <!-- 开启延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
MyBatis的缓存
一级缓存
默认开启。
一级缓存也称之为session级别的缓存,也就是说在一次会话中执行相同的查询时,会首先查询缓存,如果缓存没有数据,则直接查询数据库,并且给缓存放一份。sqlSession的缓存,一次会话缓存,只有查询操作有。
所有的增删改操作会清空缓存。
测试:**@Test public void testStuIdByClassId2(){ Student student = sqlSession.selectOne("com.quail.dao.StudentDao.queryByStudentId",3l); System.out.println(student); // 查询两次 Student student1 = sqlSession.selectOne("com.quail.dao.StudentDao.queryByStudentId",3l); System.out.println(student1); }
结果:
测试增删改,清空缓存:@Test public void testStuIdByClassId2(){ Student student = sqlSession.selectOne("com.quail.dao.StudentDao.queryByStudentId",3l); System.out.println(student); // 修改 student.setStuName("旗木卡卡西"); sqlSession.update("com.quail.dao.StudentDao.updateStuName",student); Student student1 = sqlSession.selectOne("com.quail.dao.StudentDao.queryByStudentId",3l); System.out.println(student1); }
其他清除缓存的操作:
- 提交事务
sqlSession.commit();
- 手动清除事务
sqlSession.clearCache();
- 关闭链接,并且开启了新的连接
sqlSession.close();
二级缓存
二级缓存又叫sessionFatory级别的缓存。可以在两个session(事务)之间共享数据。二级缓存默认不开启,需要手动开启。
在映射文件中手动开启二级缓存:<!-- 开启二级缓存,readOnly:是否只读 --> <cache eviction="FIFO" flushInterVal="60000" size="512" readOnly="true" />
动态SQL
if标签
<select id="queryByNameAndGender" parameterType="com.quail.pojo.Student" resultType="com.quail.pojo.Student"> select * from student where 1 = 1 <if test="stuName != null and stuName != ''"> and stuName like '%${stuName}%' </if> <if test="stuGender != null and stuGender != -1"> and stuGender = #{stuGender} </if> </select>
@Test public void testSql_if(){ Student student = new Student(); student.setStuName("q"); student.setStuGender(0); List<Student> students = sqlSession.selectList("com.quail.dao.StudentDao.queryByNameAndGender", student); for (Student student1 : students) { System.out.println(student1); } }
choose/when/otherwise
<select id="queryByNameAndGender" parameterType="com.quail.pojo.Student" resultType="com.quail.pojo.Student"> select * from student where 1 = 1 <choose> <when test="stuName != null and stuName != ''"> and stuName like '%${stuName}%' </when> <when test="stuGender!=null and stuGender!=-1"> and stuGender = #{stuGender} </when> <otherwise> <!-- 其他条件 --> </otherwise> </choose> </select>
trim/where/set
- where
处理where语句块的, 有了where标签,我们就不用使用“where 1 =1 ”。标签会自动判断,去掉多余的and。
<select id="queryByNameAndGender2" parameterType="student" resultMap="stuResultMapping">
select * from student
<!-- 自动添加where语句块,并且删除多余的 “and” -->
<where>
<!-- test里面判断时,直接写属性名称 -->
<if test="studentName!=null and studentName!=''">
and stuName like '%${studentName}%'
</if>
<if test="stuGender!=null and stuGender!=-1">
and stuGender = #{stuGender}
</if>
</where>
</select>
- set
处理update语句中的set部分。添加set字样,删除多余的“,”
<!-- set标签 -->
<update id="updateStudent" parameterType="student">
update student
<set>
<if test="studentName!=null and studentName!=''">
stuName=#{studentName},
</if>
<if test="loginPass!=null and loginPass!=''">
longinPass=#{loginPass},
</if>
<if test="stuGender!=null and stuGender!=-1">
stuGender=#{stuGender}
</if>
</set> where stuId=#{stuId}
</update>
- trim
和where等价的trim:
<select id="queryByNameAndGender3" parameterType="student" resultMap="stuResultMapping">
select * from student
<!-- prefiex:最前面添加一个where字样 -->
<!-- prefixOverrides:取出前面多余的(and或者or)字样 -->
<trim prefix="where" prefixOverrides="and | or">
<!-- test里面判断时,直接写属性名称 -->
<if test="studentName!=null and studentName!=''">
and stuName like '%${studentName}%'
</if>
<if test="stuGender!=null and stuGender!=-1">
and stuGender = #{stuGender}
</if>
</trim>
</select>
和set等价的trim:
<update id="updateStudent1" parameterType="student">
update student
<!-- prefix:添加set字样 suffixOverrides:删除多余的后缀(“,”) -->
<trim prefix="set" suffixOverrides=",">
<if test="studentName!=null and studentName!=''">
stuName=#{studentName},
</if>
<if test="loginPass!=null and loginPass!=''">
longinPass=#{loginPass},
</if>
<if test="stuGender!=null and stuGender!=-1">
stuGender=#{stuGender}
</if>
</trim> where stuId=#{stuId}
</update>
foreach标签
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和
索引(index)变量。
<!-- foreach标签 -->
<select id="queryStudentByClassIds" resultMap="stuResultMapping">
select * from student where classId in
<foreach collection="list" index="index" item="cid" separator="," open=" (" close=")">
#{cid}
</foreach>
</select>