文章目录
第三天
Mybatis 连接池与事务控制深入
Mybatis 中连接池使用及分析
Mybatis 的事务控制分析
Mybatis 的动态 SQL 语句
mappers配置文件中的几个标签
<if>
<where>
<foreach>
<sql>
Mybatis 多表操作
一对一
一对多
多对多
Mybatis 连接池与事务深入
Mybatis 连接池的分类
在 Mybatis 中也有连接池技术,但是它采用的是自己的连接池技术。在 Mybatis 的 SqlMapConfig.xml 配置文件中,通过来实现 Mybatis 中连接池的配置
Mybatis 数据源分为三类:
UNPOOLED:不使用连接池的数据源
Mybatis实现了java.sql.DataSource 接口的UnpooledDataSource 类,无连接池思想。
POOLED:使用连接池的数据源
Mybatis实现了java.sql.DataSource 接口的PooledDataSource 类
JNDI :使用JNDI 实现的数据源
采用服务器的JNDI技术实现来获取DataSource,不同的服务器拿到的DataSource是不一样的
注意:如果不是web或者maven的war工程是不能使用的
tomcat服务器采用的连接池是dbcp连接池
连接池:用于存储连接的一个容器,容器其实就是一个集合对象,该集合必须是线程安全的,不能俩个线程拿到同一连接,该集合必须实现队列特性,先进先出。mybatis连接池采用的是自己的连接池技术,具体可以查看源码UnpooledDataSourcpe、PooledDataSource
Mybatis 的事务控制
Mybatis 框架因为是对 JDBC 的封装,所以Mybatis 框架的事务控制方式中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制。
Mybatis 的动态 SQL 语句
if标签
的多条件组合查询:根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 username 不同空时还要加入用户名作为条件
/**
* 根据传入的参数条件查询
* @param user 查询条件:有可能有用户名,或者性别...不确定性
*/
List<User> findByCondition(User user);
select id="findByCondition" resultType="user" parameterType="user">
select * from USER where 1=1
<if test="username != null">
and username = #{username}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</select>
@Test
public void testFindByCondition() {
User user = new User();
user.setUsername("老王");
//user.setSex("男");
List<User> list = dao.findByCondition(user);
for (User u : list) {
System.out.println(u);
}
}
where标签
同标签:只需要修改映射文件:
<select id="findByCondition" resultType="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标签
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USER WHERE username LIKE ‘%张%’ AND (id =10 OR id =89 OR id=16)
SELECT * FROM USER WHERE username LIKE ‘%张%’ AND id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来.
package domain;
import java.util.List;
/**
* @author: Lee
* @create: 2020-11-15 13:03
* @description: pojo对象
**/
public class QueryVo {
private User user;
private List<Integer> ids;
public User getUser() {
return user;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
public void setUser(User user) {
this.user = user;
}
}
/**
* 根据QueryVo中的ids集合条件实现范围查询
* @param vo
* @return
*/
List<User> findInIds(QueryVo vo);
<select id="findInIds" parameterType="QueryVo" resultType="user">
select * from USER
<where>
<if test="ids!=null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="id" separator=",">
#{id}<!--这个值和item的名称需要一致-->
</foreach>
</if>
</where>
</select>
@Test
public void testFindInIds() {
QueryVo vo = new QueryVo();
List<Integer> idList = new ArrayList<Integer>();
idList.add(41);
idList.add(42);
idList.add(46);
vo.setIds(idList);
List<User> userList = dao.findInIds(vo);
for (User user : userList) {
System.out.println(user);
}
}
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
Mybatis 中简化编写的 SQL 片段
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。
定义代码片段
<!-- 在映射文件中,抽取重复的语句代码片段 -->
<sql id="defaultSql">
select * from user
</sql>
引用代码片段
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="user">
<include refid="defaultSql"></include>
</select>
<!-- 根据 id 查询 -->
<select id="findById" resultType="user" parameterType="int">
<include refid="defaultSql"></include>
where id = #{uid}
</select>
Mybatis 多表查询之一对多
一对一查询(多对一)
需求
查询所有账户信息,关联查询下单用户信息。
注意:
因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如
果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。
创建实体类对象使需要实现序列化接口:实现序列化的对象才可以在数据库和文件系统写入,也可以用于网络传输
可以针对查询创建po类作为返回值类型;也可以使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。
User
package domain;
import java.io.Serializable;
import java.util.Date;
/**
* @author: Lee
* @create: 2020-11-13 18:52
* @description:
**/
public class User implements Serializable {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
public User() {
}
public User(int id, String username, Date birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
Account
package domain;
import java.io.Serializable;
/**
* @author: Lee
* @create: 2020-11-16 12:55
* @description:
**/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
private User user;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
AccountDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.AccountDao">
<!--一对一-->
<!--定义主表account封装从表user返回类型-->
<resultMap id="accountUserMap" type="account">
<!--此处的resultMap的配置和下述的列别名应该同步-->
<id property="id" column="aid"/>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<!--一对一的关系映射,配置封装user的内容-->
<association property="user" javaType="user">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</association>
</resultMap>
<select id="findAll" resultMap="accountUserMap">
<!--此处的列别名和上述的resultMap的配置应该同步-->
select u.* ,a.id aid,a.uid,a.money from user as u ,account as a where u.id=a.uid
</select>
</mapper>
一对多查询
需求:
查询所有用户信息及用户关联的账户信息。
分析:
用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息
查询出来,我们想到了左外连接查询比较合适。
Account如上
User
package domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @author: Lee
* @create: 2020-11-13 18:52
* @description:
**/
public class User implements Serializable {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
//一对多关系映射,主表实体包含从表实体的集合引用
private List<Account> accounts;
public User() {
}
public User(int id, String username, Date birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
UserDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserDao">
<!--一对多-->
<!--定义主表user封装从表account集合返回类型-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id" />
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<!--一对多的关系映射,配置封装accounts集合对象的内容-->
<collection property="accounts" ofType="account">
<id property="id" column="aid"/>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
</collection>
</resultMap>
<select id="findAll" resultMap="userAccountMap">
select u.*,a.id aid,a.uid,a.money from user u left outer join account a on u.id=a.uid
</select>
</mapper>
Mybatis 多表查询之多对多
用户与角色的多对多关系模型在数据库中是需要使用中间表(包含各自的主键)
需求:
实现查询所有角色并且加载它所分配的用户信息。
分析:
查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,而是要通过中间表(USER_ROLE 表)才能关联到用户信息。
RoleDao
package dao;
import domain.Role;
import java.util.List;
/**
* @author: Lee
* @create: 2020-11-16 22:42
* @description:
**/
public interface RoleDao {
/**
* 查询所有角色
* @return
*/
List<Role> findAll();
}
Role
package domain;
import java.io.Serializable;
import java.util.List;
/**
* @author: Lee
* @create: 2020-11-16 22:39
* @description:
**/
public class Role implements Serializable {
private Integer id;
private String roleName;
private String roleDesc;
//多对多的关系映射,一个角色可以赋予多个用户
private List<User> users;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
RoleDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.RoleDao">
<resultMap id="roleMap" type="role">
<id column="rid" property="id"/>
<result column="role_name" property="roleName"/>
<result column="role_desc" property="roleDesc"/>
<collection property="users" ofType="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</collection>
</resultMap>
<select id="findAll" resultMap="roleMap">
<!--角色有分配给用户,这个角色才有用户信息-->
select u.*,r.id rid,r.role_name,r.role_desc from role r left outer join user_role ur on r.id=ur.rid left outer join user u on ur.uid=u.id
</select>
</mapper>
相反查询用户所担任的角色
SELECT * FROM USER u LEFT OUTER JOIN user_role ur ON u.id=ur.uid
SELECT u.*,r.id roleid,r.role_name,r.role_desc,ur.* FROM USER u LEFT OUTER JOIN user_role ur ON u.id=ur.uid LEFT OUTER JOIN role r ON r.id = ur.rid
JNDI
可以成功运行,但是报错:… is not bound in this context…