Mybatis
1.什么是Mybatis
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
2.Mybatis的作用域和生命周期
- SqlSessionFactoryBuilder 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。
- SqlSessionFactory SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是应用作用域。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
- SqlSession 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理作用域中,比如 Servlet 架构中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。下面的示例就是一个确保 SqlSession 关闭的标准模式:
public class DBTools {
public static SqlSessionFactory sessionFactory;
static{
try {
// 方式一
//使用MyBatis提供的Resources类加载mybatis的配置文件
//Reader reader = Resources.getResourceAsReader("mybatis.cfg.xml");
//构建sqlSession的工厂
//sessionFactory = new SqlSessionFactoryBuilder().build(reader);
// 方式二
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
//创建能执行映射文件中sql的sqlSession
public static SqlSession getSession(){
return sessionFactory.openSession();
}
}
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
3.xml配置
configuration 配置
- properties 属性
- settings 设置
- typeAliases 类型别名
- typeHandlers 类型处理器
- objectFactory 对象工厂
- plugins 插件
- environments 环境
- environment 环境变量
- transactionManager 事务管理器 (JDBC/MANAGED)
- dataSource 数据源 (POOLED/UNPOOLED/JNDI)
- environment 环境变量
- databaseIdProvider 数据库厂商标识
- mappers 映射器
3.1 properties
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:
- 在 properties 元素体内指定的属性首先被读取。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的是 properties 属性中指定的属性。
3.2 settings
延迟加载配置
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载,即延迟加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
如果想单个开启或禁用延迟加载,可以使用fetchType属性来实现,fetchType="lazy" 表示使用懒加载 fetchType="eager"表示禁用懒加载。
自动映射级别配置
<setting name="autoMappingBehavior" value="PARTIAL"/>
其中 NONE 表示不启用自动映射,PARTIAL 表示只对非嵌套的 resultMap 进行自动映射,FULL 表示对所有的 resultMap 都进行自动映射。默认的自动映射模式为 PARTIAL。
如果在某些 resultMap 中不想使用自动映射,则可以单独在该 resultMap 中设置 autoMapping 的属性为 false。
3.3 typealiases
方式一:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
方式二:
<typeAliases>
<package name="domain.blog"/> <-- 包名 -->
</typeAliases>
方式三:(优先级最高)
@Alias("author")
public class Author {
...
}
3.4 mappers
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
4.XML映射文件
4.1 高级结果映射(association,collection)
一对一或多对一(多个学生一个数学老师)
<resultMap type="Student" id="studentMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="class_name" property="className"/>
<result column="teacher_id" property="teacherId"/>
<association property="teacher" select="getTeacher" column="teacher_id" javaType="Teacher">
<!-- 这里要注意的是column对应的是student中的外键,而且需是表字段名 -->
</association>
</resultMap>
<select id="getStudent" resultMap="studentMap">
SELECT
s.id,
s.name,
s.class_name,
s.teacher_id
FROM
student s
</select>
<select id="getTeacher" resultType="Teacher" parameterType="int">
SELECT
t.id,
t.name,
t.class_name as className
FROM teacher t
where id = #{teacher_id}
</select>
一对多(一个老师对多个学生)
<!-- 方式一 -->
<resultMap type="Teacher" id="teacherMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="students" ofType="Student" column="id">
<id column="sid" property="id"/><!-- 这里的column对应的是下面查询的别名,而不是表字段名 -->
<result column="sname" property="name"/><!-- property对应JavaBean中的属性名 -->
<result column="className" property="className"/>
</collection>
</resultMap>
<!-- 查询所有的老师级各自的所有学生 -->
<select id="getTeachers" parameterType="Teacher" resultMap="teacherMap">
SELECT
t.id,
t.NAME,
t.class_Name,
s.id AS sid,
s. NAME AS sname,
s.class_name as className
FROM
teacher t
LEFT JOIN student s ON t.id = s.teacher_id
</select>
<!-- 方式二(推荐) -->
<resultMap type="Teacher" id="teacherMaps">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="class_name" property="className"/>
<collection property="students" ofType="Student" select="getStudents" column="id">
</collection>
</resultMap>
<!-- 查询所有的老师级各自的所有学生 -->
<select id="getAllTeacher" parameterType="Teacher" resultMap="teacherMaps">
SELECT
t.id,
t.NAME,
t.class_name
FROM
teacher t
</select>
<select id="getStudents" parameterType="int" resultType="Student">
select
s.id,
s. NAME,
s.class_name as className
from student s
where teacher_id = #{id}
</select>
4.2 mybatis 入参方式
- 基本类型及其封装类型,String类型
- 单个参数
- 多个参数
// 占位符方式
public Good selectGood(String id, String name);
<select id="selectGood" resultMap="GoodMap">
select * from good where id = #{0} and name=#{1}
</select>
// @Param("") 注解方式
public Good selectGood(@param("id")String id,@param("name")String name);
<select id="selectGood" resultMap="GoodMap">
select * from good where id = #{id} and name=#{name}
</select>
- 对象类型,Map类型
- List,数组类型
- List类型,parameterType设置为java.util.List或者list,< foreach>标签中collection设置为list
- 数组类型,parameterType设置为array,< foreach>标签中collection设置为array。
注:
判断List是否为空:
<if test="golfCourseList != null and golfCourseList.size() > 0">
判断Array是否为空:
<if test="object != null and object.length > 0">
4.2 mybatis 返回值类型
- 基本数据类型(int String等)
..................
- JavaBean类型
..................
- List类型
..................
- Map类型
1.返回单条数据
Map<String,****> select(****);
<select id="***" resultType="map">****************************</>
最后封装进map中数据格式为 key:数据库字段 value:字段对应值
2.返回多条数据
@MapKey("id")
Map<String,Student> select(****);
<select id="***" resultType="map">****************************</>
最后封装进map中数据格式为 key:@Mapkey设置的字段值 value:Student
5.Mybatis动态sql
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<trim prefix="SET" suffixOverrides=",">
...
</trim>
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>