Mybatis学习日志三
学习目标
- 能够使用mybatis提供的连接池
- 能够掌握mybatis中的动态sql
- 能够掌握一对多,多对多的配置
1 mybatis中的连接池及事务控制
-
连接池可以减少我们获取连接所消耗的时间。
-
连接池就是用于存储连接的一个容器,就是一个集合对象
- 该集合必须是线程安全的,不能两个线程拿到统一连接
- 该集合必须实现队列的特性:先进先出
1.1 mybatis中连接池使用及分析
mybatis连接池提供了3种方式配置:
配置位置:主配置文件SqlMapConfig.xml中的dataSource标签。type属性就是表示采用何种连接方式。
type属性取值分别是:
-
POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现。
-
UNPOOLED:采用传统的获取连接方式,虽然也实现了javax.sql.DataSource,但是没有实现池的思想。
-
JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到的DataSource是不一样的(如果不是web或者maven的war工程是不能使用的。Tomcat服务器采用的连接池就是dbcp连接池)
1.2 mybatis事务控制的分析
- 什么是事务
- 事务的四大特性ACID
- 不考虑隔离性会产生的3个问题
- 解决问题:四种隔离级别
mybatis中的事务是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚。
sqlSessionFactory.openSession(true);//手动提交事务改为自动提交。(不常用)
2 mybatis基于XML配置的动态SQL语句使用
if 标签:拼接查询语句
-
test属性:填写查询条件满足则拼接。
-
<!-- 根据条件查询 --> <select id="findUserByCondition" resultType="domain.User" parameterType="user"> select * from user where 1=1 <if test="username != null"> and username = #{username}; </if> </select>
注意:SQL语句中不区分大小写,#{}、test值中区分大小写,需和实体类中一致。
where标签:使得sql更清晰
<select id="findUserByCondition" resultType="domain.User" parameterType="user">
select * from user
<where>
<if test="username != null">
and username = #{username}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</where>
</select>
foreach标签:遍历查询
- collection属性:表示要遍历的集合元素
- open属性:表示语句的开始
- close属性:表示结束
- item属性:每一项生成的变量名,填充到open与close之间
- separator属性:分隔符
<!-- 根据QueryVo中的Id集合实现查询用户列表 -->
<select id="findUserByIds" resultType="user" parameterType="domain.QueryVo">
select * from user
<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>
注:#{}里的名称必须与item值相同!
sql标签:抽取重复的sql语句内容
-
id属性:该语句唯一标识符
<!-- 定义查询user的sql --> <sql id="RUser"> select * from user </sql>
include标签:引用定义好的sql标签内容
- refid属性:引用sql标签的id值
<!-- 查询所有 -->
<select id="findAll" resultType="domain.User">
<!-- select * from user -->
<include refid="RUser"></include>
</select>
3 ※mybatis中的多表操作
表之间的关系有几种:
- 一对一 一个人只有一个身份证号,一个身份证只属于一个人
- 一对多 一个老师教多个学生
- 多对一 多个学生被一个老师教
- 多对多 一门课程同时有多个学生选修,一个学生可以同时选修多门课程。
3.1 一对多查询(mybatis中的一对一)
查询所有账户的同时获取当前用户的姓名和地址信息
3.1.1 完成Account的一对一查询
在mybatis中把多对一看成了一对一。
示例:用户和账户
- 一个用户可以有多个账户
- 一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
- 建立两张表:用户表,账户表
- 让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
- 建立两个实体类:用户实体类和账户实体类
- 让用户和账户的实体类能体现出一对多的关系
- 建立两个配置文件
- 用户的配置文件
- 账户的配置文件
- 实现配置:
- 当我们查询用户时,也可以同时得到用户下所包含的账户信息
- 当我们查询账户时,也可以同时得到账户的所属用户信息
方法一:(此方法不常用!)
-
在IAccountDao接口中创建findAllAccount()方法
-
创建一个AccountUser实体类继承Account类
-
在映射文件IAccountDao.xml中创建相应配置
<!-- 查询所有账户及对应用户的姓名及地址 --> <select id="findAllAccount" resultType="domain.AccountUser"> select a.*,u.username,u.address from account a,user u where u.id = a.uid; </select>
-
在测试类中测试
方法二:
- 从表实体应该包含一个主表实体的对象引用
- 在映射文件中需要定义封装从表和主表的resultMap(这里是account和user的resultMap)
**association标签:**用户配置封装主表(一对一)
- property属性:从表中的引用元素名称
- column属性:外键是哪个字段
- javaType属性:封装到哪个实体类
<!-- 定义封装account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的映射关系,配置封装user -->
<association property="user" column="uid">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</association>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="accountUserMap">
select u.*,a.id as aid,a.uid,a.money from account a,user u where u.id = a.uid;
</select>
-
测试类
/** * 测试查询所有操作 * * @throws IOException */ @Test public void testFindALL() { //1.执行查询所有方法 List<Account> accounts = accountDao.findAll(); //2.遍历结果集 for (Account account : accounts) { System.out.println("----用户信息----"); System.out.println(account); System.out.println(account.getUser()); } }
3.1.2 完成user的一对多查询
- 主表实体应该包含从表实体的集合引用以及getset方法
- 在映射文件中需要定义封装从表和主表的resultMap(这里是account和user的resultMap)
**collection标签:**用于配置user对象中从表的集合(一对多)
-
property属性:值填实体中的集合引用名称
-
oftype属性:集合中元素的类型
<!-- 定义封装account和user的resultMap -->
<resultMap id="allUserAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 一对一的映射关系,配置封装account -->
<collection property="accounts" ofType="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!-- 查询用户的同时查询其账户的所有信息 -->
<select id="findAll" resultMap="allUserAccountMap">
select * from user u left outer join account a on a.uid = u.id;
</select>
- 测试类
@Test
public void testFindALL() {
//1.执行查询所有方法
List<User> users = userDao.findAll();
//2.遍历结果集
for (User user : users) {
System.out.println("----每个用户的信息----");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
3.2 多对多查询
示例:用户和角色
- 一个用户有多个角色
- 一个角色可以赋予多个用户
步骤:
- 建立两张表:用户表,角色表
- 让用户表和角色表之间具备多对多的关系:需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
- 建立两个实体类:用户实体类和角色实体类
- 让用户和角色的实体类能体现出多对多的关系
- 各自包含对方一个集合引用
- 建立两个配置文件
- 用户的配置文件
- 角色的配置文件
- 实现配置:
- 当我们查询用户时,也可以同时得到用户的角色信息
- 当我们查询角色时,也可以同时得到符合该角色的用户信息
3.2.1 查询角色时相应查询赋予的用户
与3.1.2中一对多的配置相同,但是sql语句不同。
此时sql语句需要对其角色表-中间表-用户表操作
<resultMap id="roleMap" type="role">
<id property="roleId" column="role_id"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="roleMap">
select * from role r left outer join user_role ur on r.role_id = ur.rid left outer join user u on ur.uid = u.id;
</select>
3.2.2 查询用户时相应查询对应的角色信息
与3.2.1sql语句的不一样
<resultMap id="userMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<collection property="roles" ofType="role">
<id property="roleId" column="role_id"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userMap">
select *
from user u
left outer join user_role ur on u.id = ur.uid
left outer join role r on r.role_id = ur.rid;
</select>
源自黑马+自我总结,如有错误之处望指出。