Mybatis
MyBatis 是一款优秀的持久层框架
准备环境
<!--mybatis依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
核心实例
MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的,通过 SqlSessionFactoryBuilder 构建出
MyBatis 包含一个名叫 Resources 的工具类,使得从类路径或其它位置加载资源文件
private static SqlSessionFactory sqlSessionFactory;
static {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSessionFactory() {
return sqlSessionFactory.openSession();
}
核心配置文件
mybatis-config.xml
包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)
<?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">
<!--mybatis核心配置文件-->
<configuration>
<environments default="development">
<environdement id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--mysql驱动-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://47.93.39.25:3306/tmy?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="TianMeng_yu123!@#"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/tmy/dao/UserMapper.xml"/>
</mappers>
</configuration>
configuration(配置)
properties(属性) // 属性配置,resource="mysql.properties"
settings(设置) // mybatis设置:缓存设置、超时时间、驼峰命名自动映射、日志体现...
cacheEnabled:cacheEnabled(全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true)
typeAliases(类型别名) // 在xml配置文件中使用,给java实体类设置别名或者指定包(包下实体别名为驼峰命名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置) // 配置多套数据源,默认default
environment(环境变量) // 具体环境变量
transactionManager(事务管理器) // type=JDBC(提交/回滚)
dataSource(数据源) // type=POOLED(连接池)
databaseIdProvider(数据库厂商标识)
/*
相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名
*/
mappers(映射器) // 映射器:定义 SQL 映射语句
<!-- 使用相对于类路径的资源引用:映射mapper.xml文件 -->
<mapper resource="com/tmy/dao/UserMapper.xml"/>
<!-- 使用映射器接口实现类的完全限定类名:映射mapper接口文件,使用注解 -->
<mapper class="com.tmy.dao.UserMapper"/>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<package name="com.tmy.dao"/>
映射文件
/*
select
id: 命名空间中唯一的标识符,方法名
parameterType:参数的类全限定名或别名
resultType:返回结果的类全限定名或别名(如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型)
*/
User findById(Integer id);
<select id="findById" parameterType="integer" resultType="user">
select * from user where id = #{id}
</select>
/*
insert
session 提交事务(session.commit();)
无返回值类型,但是返回操作行数
*/
<insert id="add" parameterType="user">
insert into user (id, name, age, address) values (#{id},#{name},#{age},#{address})
</insert>
/*
update
主键不能修改,这是查询的条件
*/
<update id="update" parameterType="user">
update user set
id = #{id},
name = #{name},
age = #{age},
address = #{address}
where id = #{id}
</update>
/*
delete
*/
<delete id="del" parameterType="user">
delete from user where id = #{id}
</delete>
/*
map 所有参数都可以用map来定义,不一定是实体
#{id}:id与map的key值对应,传入的值取map的value
*/
<select id="findByMapId" parameterType="map" resultType="user">
select * from user where id = #{id}
</select>
limit
注意limit页数
<select id="listLimitUser" parameterType="map" resultType="user">
select * from user limit #{pageNo},#{pageSize}
</select>
sql片段
sql 中还可以传递参数
<sql id="select">select * </sql>
<select id="listLimitUser" parameterType="map" resultType="user">
<include refid="select"></include>
from user limit #{pageNo},#{pageSize}
</select>
结果集映射(重要)
TeacherTable:id,name
StudentTable:id,name,tid(外键关联Teacher表id)
Teacher:id,name,Liststudents
Student:id,name,tid
一对多
<!--查询一个老师信息-->
<!--1、嵌套:select查询-->
<select id="findTeacher" resultMap="TeacherStudent">
select * from teacher where id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="listStudent" />
</resultMap>
<select id="listStudent" resultType="student">
select * from student where tid=#{tid}
</select>
<!--2、嵌套:结果映射处理-->
<select id="findTeacher" parameterType="int" resultMap="TeacherStudent">
select t.id tid, t.name tname, s.id sid, s.name sname from teacher t
left join student s
on t.id=s.tid
where t.id = #{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result Property="name" column="tname"/>
<collection property="students" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
</collection>
</resultMap>
Student:id,name,teacher
Teacher:id,name
多对一
<!--查询所有学生信息-->
<!--1、嵌套:select查询-->
<select id="listStudent" resultMap="StudenTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<!--单独处理学生中的老师对象-->
<association property="teacher" column="tid" javaType="Teacher" select="listTeacher" />
</resultMap>
<select id="listTeacher" resultType="Teacher">
select * from teacher where id=#{id}
</select>
<!--2、嵌套:结果映射处理-->
<select id="listStudent" resultMap="StudentTeacher">
select s.id sid, s.name sname, t.name tname
from student s, left join teacher t
on s.tid=t.id
</select>
<resultMap id="StudentTeacher">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javeType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
注解
@Select(" select * from user ")
List<User> listAll();
@Select(" select * from user where id = #{id} and name = #{name} ")
User findBy(@Param("id") Integer id, @Param("name") String name);
@Insert(" insert into user (id, name, age, address) " +
" values (#{id}, #{name}, #{age}, #{address}) ")
int add(User user);
@Update(" update user set name = #{name}, age = #{age}, address = #{address} " +
" where id = #{id} ")
int update(User user);
@Delete(" delete from user where id=#{id} ")
int del(@Param("id") Integer id);
动态sql
<!--if-->
where 后面有固定条件情况下 1=1
<if test="title != null">
and title like #{title}
</if>
<!--bind-->
创建一个变量
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
<!--where-->
where只会在子元素返回才插入 “WHERE” 子句。若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<where>
<if test="state != null">
and state = #{state}
</if>
<if test="title != null">
and title like #{title}
</if>
</where>
<!--set-->
动态更新语句set,会删掉额外的逗号
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio},</if>
</set>
where id=#{id}
<!--choose-->
<where>
<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>
</where>
<!--foreach-->
在构建 IN 条件语句
<select id="listInIds" resultType="user" parameterType="map">
select * from user
<where>
<when test="title != null">
and title like #{title}
</when>
<foreach item="id" collection="ids" open="and (" separator="," close=")">
id = #{id}
</foreach>
</where>
</select>
缓存(Cache)
存在内存中的临时数据
解决读写问题(并发):读写分离,主从复制
mybatis中定义了两级缓存:一级缓存(sqlSession)、二级缓存(nameSpace),默认情况下,一级缓存开启
一级缓存
本地缓存,sqlSession级别的
二级缓存
全局缓存,nameSpace级别的
二级缓存是事务性的。
SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句,缓存会获得更新。
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
eviction 清除策略
LRU – 最近最少使用:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
flushInterval(刷新间隔)
size 欲缓存对象的大小
readOnly (只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
一级缓存的sqlSession关闭后,二级缓存开启的化,已有的缓存就会返回给二级缓存
自定义缓存
<cache type="com.domain.something.MyCustomCache"/>