1.Mybatis中的连接池和事务控制
连接池:是一个存储连接的容器, 其实就是一个必须满足线程安全(一个线程只能对应一个连接)的集合对象,同时该集合还满足队列的特性,先进先出(先初始化的先被使用)。使用连接池技术可以减少获取连接所用的时间。
mybatis连接池:提供了三种方式的配置,主配置文件中的dataSource标签的type属性就是确定连接池的方式。
type属性取值分为三种:
POOLED:采用传统的javax.sql.DataSource规范中连接池,mybatis中有该接口规范的实现。
UNPOOLED:采用传统获取连接的方式,虽然也实现了DateSource接口但没有用到池的概念。
JNDI:使用服务器的JNDI技术实现,获取DataSource对象,不同的服务器 拿到的不一样,例如tomcat服务器使用的是dbcp连接池
不难发现,开发中使用的最多的是POOLED,他是mybatis自己的一个连接池实现,其原理研究源码可以发现。
事务概念: 事务处理在数据库开发中有着非常重要的作用,所谓事务就是所有的操作要么一起成功,要么一起失败,事务本身具有原子性(Atomicity)、一致性(Consistency)、隔离性或独立性(Isolation)、持久性(Durability)4 个特
性(ACID )。
mybatis中的事务提交和回滚:
获取sqlSession核心对象时SqlSessionFactory.openSession(true);括号内选择true,则会自动提交,手动提交和回滚需要调用SqlSession的commit()和rollback()方法。
2.Mybatis中基于xml配置的动态SQL使用
- mapper基于XML配置的标签使用:
if标签:
当查询条件不确定时(多个),但是接收参数为一个对象时,可以根据获取的参数来进行动态查询(参数使用了别名)
<!--根据多参数的动态拼接sql条件查询 -->
<select id="findByCondition" resultType="fun.borened.domain.User" parameterType="user">
select *from user where 1=1
<!--test是判断对象的属性,加上拼接动态sql参数 -->
<if test="username!=null">
and username= #{username}
</if>
<if test="sex==''">
and sex= #{sex}
</if>
</select>
where标签:
使用where标签可以省去 where 1=1,使查询语句永远为真的条件。
只需要在where标签里面在写if标签就可以达到相同的目的。
foreach标签:
当需求是查询一个属性在指定数据集的返回结果集,例如select *from user where id in(1,2,4),这时候就需要使用foreach标签来循环拼接sql。
假设User对象中有一个属性名为ids的list集合,这时需要查询id在ids集合的结果集
示例如下:注意item的值必须和下面的#{}一致,因为这是我们设置的循环变量。
<select id="findByCondition" resultType="fun.borened.domain.User" parameterType="user">
select *from user
<!--test是判断属性ids -->
<where>
<if test="ids!= null and ids.size()>0">
<foreach collection="ids" open="and id in(" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
方法体中测试:
User u = new User();
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(4);
u.setIds(list);
List<User> ulist = userDao.findByCondition(u);
for (User user : ulist) {
System.out.println(user);
}
输出结果:
sql标签:
sql标签用于避免重复sql太多的时候,减少代码量。例如提出精简的查询的sql语句:
<!--抽取重复的sql,这条sql后最后不要加分号,避免拼接时出错 -->
<sql id="findsql">
select * from user
</sql>
<!--配置查询所有 id值必须是dao中的方法名 -->
<select id="findAll" resultType="fun.borened.domain.User">
<include refid="findsql"></include>
<!-- select * from user -->
</select>
3.Mybatis中的多表查询
多对一,获取多的一方时,主表实体类中(多的一方)需要有从表(一的一方)的对象引用
一对多,主表实体类中需要有从表的实体类集合引用
多对多:两个实体类需要互相引用集合属性。
需求场景。
一个用户可以有多个账户,但是每个人账户id只能对应一个用户(user_id),用户对账户是一对多,账户对用户时多对一,上面提到了mybatis中吧多对一看成是多个一对一。
- 一对一(查询用户表和账户表中的所有有关联的用户和及其账户信息)
<!--配置返回集别名 -->
<resultMap type="account" id="accountMap">
<!--配置返回属性和数据库查询结果的列名映射,
此处由于两张表中都有id属性,给account表取别名aid作为返回结果列 -->
<id property="accountId" column="aid"/>
<result property="userId" column="user_id"/>
<result property="money" column="money"/>
<!--配置一对一的关系映射,封装user对象 ,javaType是要封装的对象 -->
<association property="user" column="user_id" javaType="user" >
<id property="id" column="id"/>
<result property="username" column="user_id"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<result property="address" column="address"/>
</association>
</resultMap>
<!--配置查询所有账户及其相关用户所有信息-->
<select id="findAll" resultMap="accountMap">
select u.*,a.id as aid,a.user_id,a.money from account a,user u where a.user_id=u.id
</select>
查询结果:可以看到user和account的信息是一一对应的
- 一对多(查询所有用户的具有全部账户信息)
<!--设置别名 -->
<resultMap type="user" id="userMap">
<id property="id" column="id"/>
<result property="username" column="user_id"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<result property="address" column="address"/>
<!--配置一对多的集合对象的映射信息 -->
<collection property="accounts" ofType="account">
<id property="accountId" column="aid"/>
<result property="userId" column="user_id"/>
<result property="money" column="money"/>
</collection>
</resultMap>
<!--配置查询有账户记录的所有用户信息和它们的账户信息 -->
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid,a.user_id,a.money from user u,account a where u.id=a.user_id
</select>
查询结果:可以看出user和account信息是一对多的结果
User [id=1, username=1, birthday=Tue Dec 10 13:00:01 CST 2019, sex=男, address=九江]-----[Account [accountId=2, userId=1, money=1500.0]
User [id=2, username=2, birthday=Tue Dec 03 13:00:22 CST 2019, sex=男, address=南昌]-----[Account [accountId=1, userId=2, money=500.0],Account [accountId=3, userId=2, money=9500.0]]
- 多对多
在数据库中,多对多的关系不能直接描述出来,需要加入中间表,在中间表中加入两张多对多表的主键栏位并以外键的形式作为中间表的两个列属性。
实体类中则需要在两个对象,都引用彼此的对象的集合形式的属性。
场景:一个用户对应多个角色,可以是学生可以是志愿者,可以是孩子
一个角色也可以对应不用的用户(人)。
查询所有用户的所属角色属性 ,测试结果如图:
xml的相关配置同一对多:
<resultMap type="user" id="userMap">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="sex" column="sex"/>
<result property="birthday" column="birthday"/>
<result property="address" column="address"/>
<!--配置一对多的集合对象的映射信息 -->
<collection property="roles" ofType="role">
<id property="roleId" column="rid"/>
<result property="roleName" column="role_name"/>
<result property="roleDesc" column="desc"/>
</collection>
</resultMap>
<!--查询当前用户相关的所有角色信息,用户和角色是多对多, -->
<select id="findAllrole" resultMap="userMap">
select u.*,r.*from user u ,role r,user_role ur where u.id=ur.user_id and r.rid=ur.role_id
</select>
一个角色也可以对应多个user,测试结果相同。