sqlmap代理池_mybatis第三天(1.连接池,2.事务控制,3.动态sql语句,4.多表查询)...

mybatis第三天该文档是:mybatis框架学习...

日期:2021-01-04

1. mybatis连接池

1.1 连接池介绍

1.2 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连接池。

POOLED 原理:

2. Mybatis的事务控制

2.1 JDBC中事务的回顾

在JDBC中我们可以通过手动方式将事务的提交改为手动方式,通过setAutoCommit()方法就可以调整。 通过JDK文档,我们找到该方法如下:

那么我们的Mybatis框架因为是对JDBC的封装,所以Mybatis框架的事务控制方式,本身也是用JDBC的setAutoCommit()方法来设置事务提交方式的。

2.2 Mybatis中事务提交方式

Mybatis中事务的提交方式,本质上就是调用JDBC的setAutoCommit()来实现事务控制。 我们运行之前所写的代码:public class MyBatisTest {

private SqlSession sqlSession;

private InputStream in=null;

//用于返回一个UserDao的代理对象

public UserDao chuShi() throws IOException {

//1.读取配置文件

in = Resources.getResourceAsStream("SqlMapConfig.xml");

//2.创建SqlSessionFactory工厂

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

SqlSessionFactory factory = builder.build(in);

//3.使用工厂生产SqlSession对象

sqlSession = factory.openSession();

//4.使用SqlSession创建Dao接口的代理对象

UserDao userDao = sqlSession.getMapper(UserDao.class);

return userDao;

}

//用于关闭连接的方法

public void destroy() throws IOException {

sqlSession.close();

in.close();

}

//测试保存用户操作

@Test

public void Test010() throws IOException {

//直接调用方法得到代理对象

UserDao userDao = chuShi();

User user = new User("曹新千",new Date(),"男","河北");

userDao.saveUser(user);

//提交事务

sqlSession.commit();

//关闭连接

destroy();

}

}

观察在它在控制台输出的结果:

这是我们的Connection的整个变化过程,通过分析我们能够发现之前的CUD操作过程中,我们都要手动进行事务的提交,原因是setAutoCommit()方法,在执行时它的值被设置为false了,所以我们在CUD操作中,必须通过sqlSession.commit()方法来执行提交操作。

2.3 Mybatis自动提交事务的设置

通过上面的研究和分析,现在我们一起思考,为什么CUD过程中必须使用sqlSession.commit()提交事务?主要原因就是在连接池中取出的连接,都会将调用connection.setAutoCommit(false)方法,这样我们就必须使用sqlSession.commit()方法,相当于使用了JDBC中的connection.commit()方法实现事务提交。

明白这一点后,我们现在一起尝试不进行手动提交,一样实现CUD操作。

所对应的DefaultSqlSessionFactory类的源代码:

运行的结果如下:

我们发现,此时事务就设置为自动提交了,同样可以实现CUD操作时记录的保存。虽然这也是一种方式,但就编程而言,设置为自动提交方式为false再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交。

3. 动态sql语句

3.1 标签

我们根据实体类的不同取值,使用不同的SQL语句来进行查询。比如在id如果不为空时可以根据id查询,如果username不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。

(1)UserDao接口增加方法/**

* 根据用户信息,查询用户列表

* @param user

* @return

*/

List findByUser(User user);

(2)UserDao.xml配置文件增加

注意:标签的test属性中写的是对象的属性名,如果是包装类的对象要使用OGNL表达式的写法。

SELECT * FROM user WHERE 1=1

AND username = #{username}

AND id = #{id}

(3)测试程序

这样的话只要id有值就根据id查,只要name有值就根据name查,两个都有就根据两个一起查//测试根据id或者名字

@Test

public void Test07() throws IOException {

UserDao userDao = chuShi();

//设置User只有名字

User user1=new User();

user1.setUsername("老王");

List users1 = userDao.findByUser(user1);

//设置User只有id

User user2=new User();

user2.setId(48);

List users2 = userDao.findByUser(user2);

System.out.println(users1);

System.out.println(users2);

destroy();

}

3.2 标签

为了简化上面where 1=1的条件拼装,我们可以采用标签来简化开发。

(1)UserDao.xml配置文件增加

SELECT * FROM user

AND username = #{username}

AND id = #{id}

3.3 标签

传入多个id查询用户信息,用下边两个sql实现:

SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)

SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)

这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。 这样我们将如何进行参数的传递?

(1)QueryVo实体类public class QueryVo {

private User user;

private List ids;

//get set方法

}

(2)UserDao接口增加方法/**

* 根据QueryVo中提供的id集合,查询用户信息

* @param queryVo

* @return

*/

List findUserInIds(QueryVo queryVo);

(3)UserDao.xml配置文件增加

SQL语句:select 字段 from user where id in (?)

标签用于遍历集合,它的属性:

collection:代表要遍历的集合元素,注意编写时不要写#{}

open:代表语句的开始部分

close:代表结束部分

item:代表遍历集合的每个元素,生成的变量名(会放到open和close的中间 每个数字用,隔开,类似于 id in (1,2,3)

sperator:代表分隔符

SELECT * FROM USER

#{id}

(4)测试程序//测试根据Query中的集合来进行查询

@Test

public void Test08() throws IOException {

UserDao userDao = chuShi();

//往QueryVo对象里边设置数组集合

QueryVo vo=new QueryVo();

List ids=new ArrayList<>();

ids.add(46);

ids.add(47);

ids.add(48);

vo.setIds(ids);

//根据集合内容查询

List users = userDao.findUserInIds(vo);

System.out.println(users);

destroy();

}

3.4 标签

Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。

(1)UserDao.xml配置文件增加

SELECT * FROM user

#{id}

4. Mybatis多表查询

4.1 一对一和一对多查询

4.1.1 分析

4.1.2 数据库表

用户表:

账户表:

4.1.3 准备工作

(1)编写Account实体类:public class Account implements Serializable {

private Integer id;

private Integer uid;

private Double money;

//get set方法

}

(2)编写AccountDao接口:public interface AccountDao {

/**

* 查询所有账户

* @return

*/

List findAll();

}

(3)编写AccountDao.xml配置文件:<?xml version="1.0" encoding="UTF-8"?>

/p>

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

SELECT * FROM account

(4)编写测试:public class AccountTest {

private SqlSession sqlSession;

private InputStream in=null;

//用于返回一个AccountDao的代理对象

public AccountDao chuShi() throws IOException {

//1.读取配置文件

in = Resources.getResourceAsStream("SqlMapConfig.xml");

//2.创建SqlSessionFactory工厂

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

SqlSessionFactory factory = builder.build(in);

//3.使用工厂生产SqlSession对象

sqlSession = factory.openSession();

//4.使用SqlSession创建Dao接口的代理对象

AccountDao accountDao = sqlSession.getMapper(AccountDao.class);

return accountDao;

}

//用于关闭连接的方法

public void destroy() throws IOException {

sqlSession.close();

in.close();

}

/**

* 测试查询所有

*/

@Test

public void Test01() throws IOException {

AccountDao accountDao = chuShi();

List accounts = accountDao.findAll();

for (Account account : accounts) {

System.out.println(account);

}

}

}

执行结果:

4.1.4 实现一对一 - 方法①(用的不多)

通过写acoount子类的方式完成一对一。

(1)分析SQL语句该怎么做:

执行该语句可以得到想要的结果,根据结果编写一个实体类可以让数据封装进去。SELECT a.*,u.username,u.address FROM user u,account a WHERE u.id=a.uid;

执行结果:

(2)编写Account子类AccountUser:

从父类那继承了id,uid,money。所以只需要再加两个属性,就能把sql语句得到的结果封装进去。public class AccountUser extends Account{

private String username;

private String address;

@Override

public String toString() {

//这里先执行父类的toString方法

return super.toString()+" AccountUser{" +

"username='" + username + '\'' +

", address='" + address + '\'' +

'}';

}

//getset方法

}

(3)编写AccountDao接口:/**

* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息

* @return

*/

List findAllAccountUser();

(4)编写AccountDao.xml配置文件:

SELECT a.*,u.username,u.address FROM user u,account a WHERE u.id=a.uid

(5)编写测试:/**

* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息

*/

@Test

public void Test02() throws IOException {

AccountDao accountDao = chuShi();

List accounts = accountDao.findAllAccountUser();

for (AccountUser account : accounts) {

System.out.println(account);

}

}

执行结果:

4.1.5 实现一对一 - 方法②(常用)

建立实体类关系的方式。

(1)编写Account实体类:

在Account类中加入User类的对象作为Account类的一个属性。public class Account implements Serializable {

private Integer id;

private Integer uid;

private Double money;

private User user;

//get set方法

}

(2)编写AccountDao接口:/**

* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息

* @return

*/

List findAll();

(3)编写AccountDao.xml配置文件:

SELECT a.*,u.username,u.address FROM user u,account a WHERE u.id=a.uid

(4)编写测试:/**

* 测试查询所有账户,同时获取账户的所属用户名称以及它的地址信息

*/

@Test

public void Test01() throws IOException {

AccountDao accountDao = chuShi();

List accounts = accountDao.findAll();

for (Account account : accounts) {

System.out.println("每一个账户:");

System.out.println(account);

System.out.println(account.getUser());

}

}

执行结果:

4.1.6 实现一对多

给数据库account表增加一个账户,uid和第一个相同:

需求和分析:

(1)分析SQL语句该怎么做:

执行该语句可以得到想要的结果,根据结果编写User类增加一个属性存放Account,这里使用List因为一个人可能有多个账户。SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT JOIN account a ON u.id=a.uid;

执行结果:

(2)编写User类:public class User implements Serializable {

private Integer id;

private String username;

private Date birthday;

private String sex;

private String address;

//一对多映射关系:主表实体应该包含从表的集合引用

//这里用List是因为,一个用户可能有多个账户

private List accounts;

//get set方法

}

(3)编写UserDao接口:/**

* 查询所有用户,同时获取到用户下所有账户的信息

* @return

*/

List findAll();

(4)编写UserDao.xml配置文件:

SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT JOIN account a ON u.id=a.uid

(5)编写测试:/**

* 查询所有用户包含账户信息

*/

@Test

public void Test01() throws IOException {

UserDao userDao = chuShi();

List users = userDao.findAll();

for (User user : users) {

System.out.println("-------每个用户的信息-------");

System.out.println(user);

System.out.println(user.getAccounts());

}

}

执行结果:

根据结果发现mybatis可以自动识别如果一个用户有多个账户的情况,并且会封装到集合中。

4.2 多对多查询

4.2.1 分析

通过前面的学习,我们使用Mybatis 实现一对多关系的维护。多对多关系其实我们看成是双向的一对多关系。

4.2.2 数据库表

用户表:

角色表:

用户角色中间表:

4.2.3 准备工作

(前情提要)这是User类:public class User implements Serializable {

private Integer id;

private String username;

private Date birthday;

private String sex;

private String address;

}

(1)编写Role实体类:public class Role {

private Integer roleid;

private String roleName;

private String roleDesc;

//get set方法

}

(2)编写RoleDao接口:public interface RoleDao {

/**

* 查询所有角色

* @return

*/

List findAll();

}

(3)编写RoleDao.xml配置文件:

SELECT * FROM role

(4)编写测试:public class RoleTest {

private SqlSession sqlSession;

private InputStream in=null;

//用于返回一个RoleDao的代理对象

public RoleDao chuShi() throws IOException {

//1.读取配置文件

in = Resources.getResourceAsStream("SqlMapConfig.xml");

//2.创建SqlSessionFactory工厂

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

SqlSessionFactory factory = builder.build(in);

//3.使用工厂生产SqlSession对象

sqlSession = factory.openSession();

//4.使用SqlSession创建Dao接口的代理对象

RoleDao roleDao = sqlSession.getMapper(RoleDao.class);

return roleDao;

}

//用于关闭连接的方法

public void destroy() throws IOException {

sqlSession.close();

in.close();

}

/**

* 查询所有角色

*/

@Test

public void Test01() throws IOException {

RoleDao roleDao = chuShi();

List roles = roleDao.findAll();

for (Role role : roles) {

System.out.println("-------每个角色的信息-------");

System.out.println(role);

}

}

}

执行结果:

4.2.4 实现查询角色获取角色下的用户信息

查询角色的同时获取到用户的信息。

(1)分析SQL语句该怎么做:

执行该语句可以得到想要的结果,根据结果在Role实体类中可以添加一个User类的集合。SELECT r.id as rid,r.role_name,r.role_desc,u.* FROM role r

LEFT JOIN user_role ur ON r.id = ur.rid

LEFT JOIN user u ON u.id=ur.uid;

执行结果:

(2)编写Role类:public class Role {

private Integer roleid;

private String roleName;

private String roleDesc;

//多对多的关系映射:一个角色可以赋予多个用户

private List users;

//get set方法

}

(3)编写RoleDao接口:public interface RoleDao {

/**

* 查询所有角色

* @return

*/

List findAll();

}

(4)编写RoleDao.xml配置文件:

SELECT r.id as rid,r.role_name,r.role_desc,u.* FROM role r

LEFT JOIN user_role ur ON r.id = ur.rid

LEFT JOIN user u ON u.id=ur.uid;

(5)编写测试:/**

* 查询所有角色

*/

@Test

public void Test01() throws IOException {

RoleDao roleDao = chuShi();

List roles = roleDao.findAll();

for (Role role : roles) {

System.out.println("-------每个角色和对应的用户信息-------");

System.out.println(role);

System.out.println(role.getUsers());

}

}

执行结果:

4.2.5 实现查询用户获取用户下的角色信息

(1)分析SQL语句该怎么做:SELECT u.*,r.id as 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;

执行结果:

(2)编写User类:public class User implements Serializable {

private Integer id;

private String username;

private Date birthday;

private String sex;

private String address;

//多对多的关系映射:一个用户可以具备多个角色

private List roles;

//get set方法

}

(3)编写UserDao接口:/**

* 查询所有用户,同时获取到用户下所有账户的信息

* @return

*/

List findAll();

(4)编写UserDao.xml配置文件:

SELECT u.*,r.id as 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;

(5)编写测试:/**

* 查询所有用户包含账户信息

*/

@Test

public void Test01() throws IOException {

UserDao userDao = chuShi();

List users = userDao.findAll();

for (User user : users) {

System.out.println("-------每个用户和对应的角色信息-------");

System.out.println(user);

System.out.println(user.getRoles());

}

}

执行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值