# 内容
1. 连接池
2. 事务
3. 动态sql语句
4. 多表查询
## mybatis的连接池
1. 连接池:
作用:可以减少获取连接的时间
2. mybatis中的连接池
1. 配置的位置:
* 主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。
2. type属性的取值:
* POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
* UNPOOLED:采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
* JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。
3. POOLED的工作原理;
1. 判断连接池中是否有空闲的连接,若有则取出连接;若无,进入下一判断
2. 判断连接池中的连接数量是否达到最大值,若未达到,新建新的连接,并置其为活动状态;若达到,进入下一判断
3. 取出最老的活动的连接,判断其是否已经失效;若失效,将连接移除并新建新的连接
## mybatis中的事务
1. 概念:
* 事务(Transaction)是并发控制单位,是用户定义的一个操作序列,这些操作要么都做,要么都不做,是一个不可分割的工作单位。
* 事务通常以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。
2. 四大特性(ACID):原子性,一致性,隔离性,持久性
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的
3. 不考虑事务的隔离性,会发生的几种问题:
1. 脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
2. 不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
* 不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
3. 虚读(幻读)
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
* 幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
4. 设置事务的自动提交
* session = factory.openSession(true);
## 动态SQL
1. if标签
* 常与test属性联合使用,是一种非此即彼的关系
<select id="findRole" parameterType="string" resultMap="roleResultMap">
select role_no,role_name,note from t_role where 1=1
<if test="roleName != null and roleName != "">
and role_Name like concat('%',#{roleName},'%')
</if>
</select>
2. chose、when、otherwise标签
* 与if标签不同,提供了三种或者更多的选择。类似与 switch...case...default
<select id="findRole" parameterType="string" resultMap="roleResultMap">
select role_no,role_name,note from t_role where 1=1
<choose>
<when test="roleName != null and roleName != '' ">
and role_Name like concat('%',#{roleName},'%')
</when>
<when test="roleNo != null and roleNo !=''">
and role_no=#{roleNo}
</when>
<otherwise>
and note is not null
</otherwise>
</choose>
</select>
3. where标签
* 当where里面的条件成立时,才会将where关键字加入到组装的SQL里面,否则不加入
<!-- 根据用户信息查询 -->
<select id="findByUser" resultType="user" parameterType="user">
<include refid="defaultSql"></include>
<where>
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</where>
</select>
4. foreach标签:用于遍历集合
* collection:代表要遍历的集合元素,注意编写时不要写#{}
* open:代表语句的开始部分
* close:代表结束部分
* item:代表遍历集合的每个元素,生成的变量名
* sperator:代表分隔符
注:queryvo类的内容如下:private User user,private List<Integer> ids,以及相应的get和set方法
<!--对应的dao的语句-->
List<User> findUserInIds(QueryVo vo);
<!-- 查询所有用户在 id 的集合之中 -->
<!-- 抽取重复的sql语句-->
<sql id="defaultUser">
select * from user
</sql>
<select id="findInIds" resultType="user" parameterType="queryvo">
<!-- select * from user where id in (1,2,3,4,5); -->
<include refid="defaultSql"></include>
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="uid" separator=",">
<!--
select * from user
where
id in (
#{uid}
)
-->
#{uid}
</foreach>
</if>
</where>
</select>
5. bind标签
* 通过OGNL表达式,自定义一个上下文变量,方便进行不同数据库模糊查询的通配符设置,提高了移植性
* name属性指定了变量的名字
* value属性指定了通配符的设置
<select id="findRole" resultType="role">
<bind name="pattern_roleName" value=" '%' + roleName + '%' "/>
<bind name="pattern_note" value=" '%' + note + '%' "/>
select id,role_name as roleName from t_role where role_Name like # {pattern_roleName} and note like #{pattern_note}
</select>
## mybatis中的多表查询
1. 表之间的关系
* 一对多
* 多对一
* 一对一
* 多对多
2. 一对一与多对一的示例说明
示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1、建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2、建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出来一对多的关系
3、建立两个配置文件
用户的配置文件 与 账户的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息
3. 多对多的示例说明
示例:用户和角色
一个用户可以有多个角色
一个角色可以赋予多个用户
步骤:
1、建立两张表:用户表,角色表
让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
2、建立两个实体类:用户实体类和角色实体类
让用户和角色的实体类能体现出来多对多的关系,各自包含对方一个集合引用
3、建立两个配置文件
用户的配置文件 与 角色的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户所包含的角色信息
当我们查询角色时,可以同时得到角色的所赋予的用户信息
4. 一对一的映射:在一边使用association级联
* 一对一级联,应该在一边的POJO(Plain Ordinary Java Object简单java对象)对象包含另一个对象的属性,从而形成级联
* 说明:在该例子中,Account的实体类中,包括了实体类User2这一属性;Account的数据库表中,包括了uid这一列外键;
* association中的javaType属性告诉Mybatis使用哪个类去映射对应的字段
* association中的column属性说明SQL中哪个字段去关联结果
<!-- 一个account对应一个user2 -->
<!-- 定义封装User2和Account的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一对一的关系映射,配置封装User2的内容 -->
<association property="user2" column="uid" javaType="user2">
<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>
5. 一与多的映射:在一的一边使用collection级联
* 一对多、多对一映射,应该在多的一边的POJO对象包含另一个对象的属性,从而形成级联
* 说明:在该例子中,User的实体类中,包括了List<Account>这一属性;Account的数据库表中,包括了uid这一列外键;
* collection中的ofType属性定义的是说明collection中的泛型是什么Java类型,Mybatis会拿定义的Java类和结果集映射
<!-- 多个account对应一个user2 -->
<!-- 定义封装User2和Account的resultMap -->
<resultMap id="userAccountMap" type="user2">
<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>
<!-- 配置User2对象中的accounts集合的映射 -->
<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>
6. 多对多的映射:在两边使用collection级联
* 多对多映射,应该在两边的POJO对象包含另一个对象的属性,从而形成级联
* 说明:在该例子中,Role实体类包括了List<User> users这一属性;User实体类包括了List<Role> roles这一属性
* 应该有第三张表两个拿两张表各自的主键作为外键,从而将二者多对多的关系联系起来
RoleDao.xml:
<!--定义role表的ResultMap-->
<resultMap id="roleUserMap" type="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDetail" column="role_desc"></result>
<collection property="users" ofType="user2">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</collection>
</resultMap>
UserDao.xml:
<!-- 定义User2的resultMap -->
<resultMap id="userAccountMap" type="user2">
<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>
<!-- 一对多的关系映射,配置封装accounts的内容 -->
<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>