内置数据源(连接池、事务管理器)
数据源
在 Mybatis 的 SqlMapConfig.xml 配置文件中,通过 <dataSource type="pooled">来实现 Mybatis 中连接池的配置。
别名对应的类:
-
POOLED:PooledDataSourceFactory ---> PooledDataSource
-
UNPOOLED:UnpooledDataSourceFactory ---> UnpooledDataSource
-
JNDI:JndiDataSourceFactory ---> JndiDataSource
POOLED
没有创建原生链接,是利用代理的方式生产链接,调用close方法时将链接归还到数据源,适用于企业级的Web应用,在面对一定并发量时,通常使用POOLED数据源优化数据库链接。
优点:
性能提升:提供复用已创建的链接,避免了频繁创建和关闭链接的开销,在高并发的场景下,更快地响应请求。
资源优化:有效管理数据库连接资源,避免了资源的浪费
稳定性增强:因为减少了链接的创建和关闭,对象的错误和异常也相对减少,提高了系统的稳定性
UNPOOLED
创建原生链接,没有对连接池进行管理,调用close方法时直接关闭链接,适用于小型、低并发的应用场景。
优点:
简单易用:配置和使用相对简单,不需要复杂的连接池管理设置
适合低并发场景:在并发量极低的情况下,不会因为连接池的管理带来额外的开销
独立运行:不依赖与连接池的机制,在某些特殊环境或需求下,可以更灵活地控制连接的行为。
JNDI(已淘汰)
数据源通过Java Naming and Directory Interface(JNDI)获取数据源,在企业级应用服务器环境中,经常会配置JNDI数据源,MyBatis可以通过配置直接使用这些已存在的数据源。
淘汰原因:
复杂性:JNDI的配置和使用相对负载,需要在应用服务器中进行一系列的设置和管理,增加了开发和维护的难度。
灵活性受限:因为复杂性高,因此在部署在不同的环境或迁移应用时,JDNI的配置可能需要大量的调整和重新配置
与现代架构不匹配:随着微服务架构和云原生应用的兴起,更加轻量级和灵活的数据源管理方式更受欢迎。JDNI过于与特点应用服务器紧密耦合。
技术更新:越来越多新技术及框架不断涌现,提供了更简单、高效、灵活的数据源管理方案。
事务管理器
JDBC
默认的事务管理器,直接使用JDBC的连接来管理事务,使用原生的JDBC提交和回滚。适用于简单的应用场景。
Configuration中JDBC别名的全称:jdbcTransactionFactory
MyBatis的配置文件:
<!--采用JdbcTransaction事务管理器来管理事务-->
<transactionManager type="JDBC"></transactionManager>
test:
@Before
public void before() throws Exception {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsReader("MyBatisConfig.xml"));
/**
* 设置是否自动提交事务:
* true: 自动提交事务,不经过事务管理器(因为JDBC连接默认就是自动提交)
* false(默认值): 手动提交事务,由于JDBC连接默认为自动提交,因此设置为false时将会使用事务管理器来回滚事务
*/
session = sessionFactory.openSession(true);
empDao = session.getMapper(EmpDao.class);
}
@After
public void after() throws Exception {
session.close();
}
@Test
public void test1() throws Exception {
empDao.delete(2);
// 使用事务管理器的commit()方法来提交事务(必须要先设置为手动提交)
session.commit();
// 使用事务管理器的rollback()方法来回滚事务
// session.rollback();
}
MANAGED
适用于应用服务器管理事务,在这种情况下,MyBatis会将事务管理委托给应用服务器
由于JDBC连接默认的策略是自动提交,因此采用MANAGED则不能回滚事务
Configuration中MANAGED别名的全称:ManagedTransactionFactory
MyBatis配置文件:
<!--采用ManagedTransaction事务管理器来管理事务-->
<transactionManager type="MANAGED"></transactionManager>
test:
@Before
public void before() throws Exception {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsReader("MyBatisConfig.xml"));
/**
* 设置是否自动提交事务:
* true: 自动提交事务,不经过事务管理器(因为JDBC连接默认就是自动提交)
* false(默认值): 手动提交事务,在Managed模式下,即使设置了false最终经过事务管理器也无法回滚事务了
*/
session = sessionFactory.openSession(true);
empDao = session.getMapper(EmpDao.class);
}
@After
public void after() throws Exception {
session.close();
}
@Test
public void test1() throws Exception {
empDao.delete(2);
// 执行ManagedTransaction的commit方法(空方法)
session.commit();
// 执行ManagedTransaction的rollback方法(空方法)
// session.rollback();
}
动态SQL
if标签
<select id="MyClassName" resultType="emp">
select * from emp where 1=1
<if test="id!=null">
and id=#{id}
</if>
<if test="name!=null">
and name=#{name}
</if>
</select>
where标签
会智能添加“where”并去除if标签中开头的“and”
<select id="findByIdAndName" resultType="emp">
select * from emp
<where>
<if test="id!=null">
and id=#{id}
</if>
<if test="name!=null">
and name=#{name}
</if>
</where>
</select>
foreach标签
传递list集合时if语句中可以使用list或collection来取值
传递set集合时if语句中只能使用collection来取值
传递数组时if语句中只能使用array来取值
<select id="findByIds" resultType="emp">
select * from emp
<where>
<!-- 使用list/collection/array获取集合的值 -->
<if test="list!=null and collection.size>0">
id in
<foreach collection="list" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
</where>
</select>
参数:
open:前缀
close:后缀
item:遍历出来的元素名称
separator:分割符
choose标签
只有当when标签都不成立时才会执行otherwise标签
<select id="findByEmp" resultType="emp">
select * from emp
<where>
<choose>
<when test="id!=null">
and id=#{id}
</when>
<when test="name!=null">
and name like #{name}
</when>
<otherwise>
and 1!=1
</otherwise>
</choose>
</where>
</select>
set标签
会智能添加“set”并去除if语句前后的“,”
<update id="update">
update emp
<set>
<if test="name != null">
name = #{name},
</if>
<if test="age != null">
age = #{age},
</if>
<if test="addr != null">
addr = #{addr},
</if>
<if test="salary != null">
salary = #{salary},
</if>
</set>
where id=#{id}
</update>
trim标签
与where标签类似,不过可以定制化去除/添加前后的关键字
<select id="findByIdOrName" resultType="emp">
select * from emp
<trim prefix="where" prefixOverrides="and|or">
<if test="id!=null">
or id = #{id}
</if>
<if test="name!=null">
or name = #{name}
</if>
</trim>
</select>
<update id="update2" parameterType="Emp">
update emp
<trim prefix="set" suffixOverrides=",">
<if test="name != null">
name = #{name},
</if>
<if test="age != null">
age = #{age},
</if>
<if test="addr != null">
addr = #{addr},
</if>
<if test="salary != null">
salary = #{salary},
</if>
</trim>
where id=#{id}
</update>
<insert id="save" parameterType="Emp">
insert into emp
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id!=null">
id,
</if>
<if test="name!=null">
name,
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id!=null">
#{id},
</if>
<if test="name!=null">
#{name},
</if>
</trim>
</insert>
参数:
属性 | 说明 |
---|---|
prefix | 给SQL语句拼接的前缀 |
suffix | 给SQL语句拼接的后缀 |
prefixOverrides | 去除的前缀 |
suffixOverrides | 去除的后缀 |
定制SQL片段
提前写好静态SQL片段(include标签中refid的value也可以是完整路径)
<sql id="findEmp">
select * from emp
</sql>
<select id="findByIds" resultType="emp">
<include refid="findEmp"></include>
<where>
<if test="collection!=null and collection.size>0">
id in
<foreach collection="collection" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
</where>
</select>
多表关联查询
一对一
手动映射
<mapper namespace="com.xxx.dao.EmpDao">
//手动映射
<resultMap id="empResultMap" type="emp">
<id column="eId" property="id"></id>
<result column="empName" property="name"></result>
<result column="addr" property="addr"></result>
<result column="salary" property="salary"></result>
<result column="deptId" property="dept.id"></result>
<result column="deptName" property="dept.name"></result>
<result column="location" property="dept.location"></result>
</resultMap>
//sql语句
<select id="findAll" resultMap="empResultMap">
SELECT
e.id eId,
e.NAME empName,
e.addr,
e.salary,
e.dept_id deptId,
d.name deptName,
d.location
FROM
emp e
LEFT JOIN dept d ON e.dept_id = d.id
</select>
</mapper>
关系映射:association标签
在使用关系映射时,即使查询出来的列明和实体类的属性名一致,也要手动映射
<resultMap id="empResultMap" type="emp">
//手动映射
<id column="eId" property="id"></id>
<result column="empName" property="name"></result>
<result column="addr" property="addr"></result>
<result column="salary" property="salary"></result>
//关系映射
<association property="dept" javaType="com.dfbz.entity.Dept">
<id column="deptId" property="id"></id>
<result column="deptName" property="name"></result>
<result column="location" property="location"></result>
</association>
</resultMap>
参数:
property:对象中的属性
javaType:属性类型
一对多:collection标签
<mapper namespace="com.xxx.dao.DeptDao">
<resultMap id="deptResultMap" type="dept">
//手动映射
<id column="deptId" property="id"></id>
<result column="deptName" property="name"></result>
<result column="location" property="location"></result>
//关系映射
<collection property="empList" ofType="com.dfbz.entity.Emp">
<id column="eId" property="id"></id>
<result column="empName" property="name"></result>
<result column="addr" property="addr"></result>
<result column="salary" property="salary"></result>
</collection>
</resultMap>
<select id="findAll" resultMap="deptResultMap">
SELECT
e.id eId,
e.NAME empName,
e.addr,
e.salary,
e.dept_id deptId,
d.NAME deptName,
d.location
FROM
emp e
right JOIN dept d ON e.dept_id = d.id
</select>
</mapper>
参数:
property:对象中的属性
ofType:集合中的泛型类型
多对多
主表在左,使用 left join
主表在右,使用 right join
<mapper namespace="com.dfbz.dao.UserDao">
<resultMap id="userResultMap" type="user">
//手动映射
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
//关系映射
<collection property="roles" ofType="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
<select id="findAll" resultMap="userResultMap">
select
u.*,
r.id rid,
r.role_name,
r.role_desc
from user u
left join user_role ur on u.id=ur.uid
left join role r on r.id=ur.rid
</select>
</mapper>