3.4.3 分页查询
后端需要知道当前请求的是哪一页,每一页显示多少条数据
前端需要知道当前页的数据以及页面的总数量
-- 分页查询的sql语句 select * from user limit ?,? 第一个?: 这一页开始的索引 (page - 1) * pageSize 第二个?: pageSize -- 查询总数量 select count(*) from user
-
UserDao接口中
/** * 分页查询 * @param page 第几页 * @param pageSize 一页显示多少条 * @return 分页的数据 */ List<User> queryUserByPage(int page,int pageSize); /** * 查询用户总数量 * @return 总数量 */ int queryUserCount();
-
UserDaoImpl中
@Override
public List<User> queryUserByPage(int page, int pageSize) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "select * from user limit ?,?";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<User> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 给?赋值
preparedStatement.setInt(1,(page - 1) * pageSize);
preparedStatement.setInt(2,pageSize);
// 执行sql语句,返回结果
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
list.add(getUser(resultSet));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
return list;
}
@Override
public int queryUserCount() {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "select count(*) from user";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
// 定义总数量
int totalRow = 0;
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 执行sql语句,获取结果集
resultSet = preparedStatement.executeQuery();
if (resultSet.next()){
totalRow = resultSet.getInt(1);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
return totalRow;
}
-
测试方法
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
int page = 1;
final int pageSize = 6;
List<User> users = userDao.queryUserByPage(page, pageSize);
int count = userDao.queryUserCount();
// 计算总共有多少页
int totalPage = (count % pageSize == 0) ? (count / pageSize) : (count / pageSize + 1);
System.out.println("总记录数是" + count);
System.out.println("总页数是" + totalPage);
users.forEach(System.out::println);
}
3.4.4 根据条件查询并分页
-- 条件 根据用户名模糊查询 根据年龄在区间范围内查询 minAge maxAge create_time区间范围内查询 beginTime endTime -- 没有条件 select * from user limit ?,? -- 用户名 select * from user where username like ? limit ?,? -- 用户名 年龄 select * from user where username like ? AND age between ? AND ? limit ?,? -- 年龄 select * from user where age between ? AND ? limit ?,? -- 动态拼接sql语句 where username like ? and age between ? and ? and create_time between ? and ?; -- 按照条件查询总数量 -- 没有条件 select count(*) from user; -- 用户名 select count(*) from user where username like ?; -- 用户名 年龄 select count(*) from user where username like ? AND age BETWEEN ? AND ?; -- 动态拼接sql语句 where username like ? and age between ? and ? and create_time between ? and ?;
-
SearchParamVo
package cn.javasm.entity;
import lombok.Data;
@Data
public class SearchParamVo {
/**
* 用户名
*/
private String nameParam;
/**
* 最小年龄
*/
private Integer minAge;
/**
* 最大年龄
*/
private Integer maxAge;
/**
* 开始时间
*/
private String beginTime;
/**
* 结束时间
*/
private String endTime;
}
-
UserDao接口
/**
* 按照条件查询并分页
* @param searchParamVo 搜索条件
* @param page 第几页
* @param pageSize 每页显示的数量
* @return 结果
*/
List<User> queryUserByParamAndPage(SearchParamVo searchParamVo,int page,int pageSize);
/**
* 获取条件查询记录的总数量
* @param searchParamVo 条件
* @return 总数量
*/
int queryUserByParamCount(SearchParamVo searchParamVo);
-
UserDaoImpl
@Override
public List<User> queryUserByParamAndPage(SearchParamVo searchParamVo, int page, int pageSize) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 拼接sql语句
StringBuilder stringBuilder = new StringBuilder();
// 拼接sql语句前面固定的内容
stringBuilder.append("select * from user");
// 动态拼接sql
appendSql(searchParamVo,stringBuilder);
// 拼接sql语句后面固定的内容
stringBuilder.append(" limit ?,? ");
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<User> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(stringBuilder.toString());
// 给?赋值
int count = setParameterCount(searchParamVo,preparedStatement);
// 给limit的?赋值
preparedStatement.setInt(count++,(page - 1) * pageSize);
preparedStatement.setInt(count,pageSize);
// 执行sql语句获取结果集
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
list.add(getUser(resultSet));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
return list;
}
@Override
public int queryUserByParamCount(SearchParamVo searchParamVo) {
// 获取连接
Connection connection = DBUtil.getConnection();
// 拼接固定的sql内容
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("select count(*) from user ");
// 动态拼接sql语句
appendSql(searchParamVo,stringBuilder);
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
// 定义变量,记录总数量
int totalRow = 0;
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(stringBuilder.toString());
// 给?赋值
setParameterCount(searchParamVo,preparedStatement);
// 执行sql语句,获取结果集
resultSet = preparedStatement.executeQuery();
if (resultSet.next()){
totalRow = resultSet.getInt(1);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
return totalRow;
}
private int setParameterCount(SearchParamVo searchParamVo,PreparedStatement preparedStatement) throws SQLException {
// 给?赋值
Integer maxAge = searchParamVo.getMaxAge();
String endTime = searchParamVo.getEndTime();
String nameParam = searchParamVo.getNameParam();
Integer minAge = searchParamVo.getMinAge();
String beginTime = searchParamVo.getBeginTime();
// 定义变量,记录参数的位置
int count = 1;
if (nameParam != null && !nameParam.isBlank()){
// 有用户名
preparedStatement.setString(count++,"%" + nameParam + "%");
}
if (minAge != null){
// 有年龄
preparedStatement.setInt(count++,minAge);
preparedStatement.setInt(count++,maxAge);
}
if (beginTime != null && !beginTime.isBlank()){
preparedStatement.setString(count++,beginTime);
preparedStatement.setString(count++,endTime);
}
return count;
}
/**
* 动态拼接sql
*/
private void appendSql(SearchParamVo searchParamVo,StringBuilder stringBuilder){
// 获取参数
String nameParam = searchParamVo.getNameParam();
Integer minAge = searchParamVo.getMinAge();
String beginTime = searchParamVo.getBeginTime();
// 判断是否已经添加where true代表添加过
boolean flag = false;
if (nameParam != null && !nameParam.isBlank()){
stringBuilder.append(" WHERE username like ? AND");
flag = true;
}
if (minAge != null){
if (!flag) {
stringBuilder.append(" WHERE ");
flag = true;
}
stringBuilder.append(" age BETWEEN ? AND ? AND");
}
if (beginTime != null && !beginTime.isBlank()){
if (!flag){
stringBuilder.append(" WHERE ");
flag = true;
}
stringBuilder.append(" create_time BETWEEN ? AND ? AND");
}
if (flag){
// 如果有条件参数,删除掉最后一个多余的AND
stringBuilder.delete(stringBuilder.lastIndexOf("AND"),stringBuilder.length());
}
}
3.4.5 多表查询
-- 查询用户的id,用户名,用户年龄,用户角色,用户的部门 select u.id,u.username,u.age,r.role_name,d.dname FROM user u,role r,dept d WHERE u.rid = r.id AND u.did = d.deptno
-
方式一
package cn.javasm.entity;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class UserRoleDeptVo {
/**
* id
*/
private Long id;
/**
* 用户名
*/
private String username;
/**
* 年龄
*/
private Integer age;
/**
* 角色名称
*/
private String roleName;
/**
* 部门名称
*/
private String dname;
}
在UserDao中提供抽象方法
/**
* 查询用户信息和角色和部门
* @return
*/
List<UserRoleDeptVo> queryUserAndRoleAndDept();
在UserDaoImpl中实现方法
@Override
public List<UserRoleDeptVo> queryUserAndRoleAndDept() {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "select \n" +
"u.id,u.username,u.age,r.role_name,d.dname\n" +
"FROM\n" +
"user u,role r,dept d\n" +
"WHERE\n" +
"u.rid = r.id\n" +
"AND\n" +
"u.did = d.deptno";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<UserRoleDeptVo> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 执行sql,获取结果集
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
long id = resultSet.getLong(1);
String username = resultSet.getString(2);
int age = resultSet.getInt("age");
String roleName = resultSet.getString(4);
String dname = resultSet.getString("dname");
// 封装成对象
UserRoleDeptVo userRoleDeptVo = new UserRoleDeptVo().setId(id).setRoleName(roleName).setAge(age).setUsername(username).setDname(dname);
list.add(userRoleDeptVo);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
return list;
}
-
方式二
定义Role类
@Data
@Accessors(chain = true)
public class Role {
/**
* 角色id
*/
private Long id;
/**
* 角色名称
*/
private String roleName;
/**
* 角色描述
*/
private String roleDesc;
}
定义部门类
@Data
@Accessors(chain = true)
public class Dept {
/**
* 部门id
*/
private int deptno;
/**
* 部门名称
*/
private String dname;
/**
* 部门地址
*/
private String loc;
}
定义UserRoleDept
@Data
@Accessors(chain = true)
public class UserRoleDept {
/**
* 用户信息
*/
private User user;
/**
* 角色信息
*/
private Role role;
/**
* 部门信息
*/
private Dept dept;
}
-
UserDao接口中
/**
* 查询用户和角色和部门信息
*/
List<UserRoleDept> queryUserAndRoleAndDeptAll();
UserDaoImpl中
@Override
public List<UserRoleDept> queryUserAndRoleAndDeptAll() {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "select \n" +
" *\n" +
"FROM\n" +
"user u,role r,dept d\n" +
"WHERE\n" +
"u.rid = r.id\n" +
"AND\n" +
"u.did = d.deptno";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<UserRoleDept> list = new ArrayList<>();
try {
// 获取预编译对象
preparedStatement = connection.prepareStatement(sql);
// 执行sql语句,获取结果集
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
User user = new User().setId(resultSet.getLong(1)).setUsername(resultSet.getString("username")).setAge(resultSet.getInt("age")).setBalance(resultSet.getBigDecimal("balance")).setCreateTime((LocalDateTime) resultSet.getObject("create_time"));
Role role = new Role().setId(resultSet.getLong(11)).setRoleName(resultSet.getString(12)).setRoleDesc(resultSet.getString(13));
Dept dept = new Dept().setDeptno(resultSet.getInt("deptno")).setDname(resultSet.getString("dname")).setLoc(resultSet.getString("loc"));
UserRoleDept userRoleDept = new UserRoleDept().setUser(user).setRole(role).setDept(dept);
list.add(userRoleDept);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
}
return list;
}
3.5 新增角色
-- 新增角色,指定角色可以执行的菜单功能 -- 展示角色对应的权限菜单功能 select * from menu; -- 在角色表中新增一条记录 insert into role (role_name,role_desc) values(?,?) -- 在中间表中添加角色和菜单的关系 insert into role_menu (rid,mid) values(?,?),(?,?)...(?,?)
-
创建Menu类
@Data
public class Menu {
/**
* id
*/
private Long id;
/**
* 菜单名称
*/
private String menuName;
/**
* 菜单地址
*/
private String menuUrl;
/**
* 菜单的父菜单id
*/
private Long parentMenuId;
public static Menu getMenu(ResultSet resultSet) throws SQLException {
Menu menu = new Menu();
menu.setId(resultSet.getLong(1));
menu.setMenuName(resultSet.getString(2));
menu.setMenuUrl(resultSet.getString(3));
menu.setParentMenuId(resultSet.getLong(4));
return menu;
}
}
-
测试类
package cn.javasm.demo;
import cn.javasm.dao.MenuDao;
import cn.javasm.dao.RoleDao;
import cn.javasm.dao.impl.MenuDaoImpl;
import cn.javasm.dao.impl.RoleDaoImpl;
import cn.javasm.entity.Menu;
import cn.javasm.entity.Role;
import java.sql.SQLException;
import java.util.List;
import java.util.Scanner;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class TestDemo {
public static void main(String[] args) throws SQLException {
// 新增角色
Scanner scanner = new Scanner(System.in);
// 角色名称
System.out.println("输入新的角色名称");
String newRoleName = scanner.next();
// 角色描述
System.out.println("输入新的角色描述");
String newRoleDesc = scanner.next();
// 层级展示菜单
MenuDao menuDao = new MenuDaoImpl();
List<Menu> menuList = menuDao.queryAll();
String str = "|- ";// |- 1 用户管理
// stream流
menuList.stream().filter(menu -> menu.getParentMenuId() == 0).peek(parentMenu -> {
System.out.println(str + parentMenu.getId() + ":" + parentMenu.getMenuName());
queryChildMenu(parentMenu,menuList,"| " + str);
}).count();
System.out.println("对" + newRoleName + "角色选择对应的菜单功能(1,2,3)");
// 获取用户输入的菜单的id
String menuIdStr = scanner.next();
String[] menuIds = menuIdStr.split(",");
// 新增角色
Role role = new Role().setRoleName(newRoleName).setRoleDesc(newRoleDesc);
RoleDao roleDao = new RoleDaoImpl();
// 添加角色后获取新增角色的id
Long rid = roleDao.insertRole(role);
// 新增中间表
int row = roleDao.insertRoleAndMenu(rid, menuIds);
System.out.println(row);
}
/**
* 层级展示子菜单
* @param parentMenu 父菜单
* @param menuList 全部菜单
* @param str 拼接字符串 美观
*/
private static void queryChildMenu(Menu parentMenu,List<Menu> menuList,String str){
menuList.stream().filter(menu -> menu.getParentMenuId() == parentMenu.getId())
.peek(menu -> {
System.out.println(str + menu.getId() + ":" + menu.getMenuName());
queryChildMenu(menu,menuList,"| " + str);
}).count();
}
private static void demo() {
// 传统写法 不适合动态菜单 只能菜单有三层
// for (Menu menu : menuList) {
// if (menu.getParentMenuId()== 0){
// System.out.println(menu.getId() + ":" + menu.getMenuName());
// for (Menu menu1 : menuList) {
// if (menu1.getParentMenuId() == menu.getId()){
// System.out.println("\t" + menu1.getId() + ":" + menu1.getMenuName());
// for (Menu menu2 : menuList) {
// if (menu2.getParentMenuId() == menu1.getId()){
// System.out.println("\t\t" + menu2.getId() + ":" + menu2.getMenuName());
// }
// }
// }
// }
// }
// }
}
}
-
MenuDao接口
public interface MenuDao {
/**
* 查询所有的菜单
* @return
*/
List<Menu> queryAll() throws SQLException;
}
-
MenuDaoImpl中
public class MenuDaoImpl implements MenuDao {
@Override
public List<Menu> queryAll() throws SQLException {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "select * from menu";
// 获取预编译对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 执行sql语句
ResultSet resultSet = preparedStatement.executeQuery();
// 创建集合
List<Menu> menuList = new ArrayList<>();
while (resultSet.next()){
menuList.add(Menu.getMenu(resultSet));
}
// 释放资源
DBUtil.release(connection,preparedStatement,resultSet);
return menuList;
}
}
-
RoleDao接口中
public interface RoleDao {
/**
* 新增角色
* @param role 角色对象
* @return 插入角色的id
*/
Long insertRole(Role role) throws SQLException;
/**
* 新增中间表
* @param rid 角色id
* @param menuIds 菜单id的数组
* @return 数据库受影响的行数
*/
int insertRoleAndMenu(Long rid,String[] menuIds) throws SQLException;
}
-
RoleDaoImpl中
public class RoleDaoImpl implements RoleDao {
@Override
public Long insertRole(Role role) throws SQLException {
// 获取连接
Connection connection = DBUtil.getConnection();
// 编写sql语句
String sql = "insert into role (role_name,role_desc) values(?,?)";
// 获取预编译对象
PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// 给?赋值
preparedStatement.setString(1,role.getRoleName());
preparedStatement.setString(2,role.getRoleDesc());
// 执行sql语句
preparedStatement.executeUpdate();
// 获取上面刚刚插入角色的id 本质上是执行last_insert_id()函数
ResultSet resultSet = preparedStatement.getGeneratedKeys();
Long autoId = 0L;
if (resultSet.next()){
autoId = resultSet.getLong(1);
}
// 释放资源
DBUtil.release(connection,preparedStatement);
return autoId;
}
@Override
public int insertRoleAndMenu(Long rid, String[] menuIds) throws SQLException {
// 获取连接
Connection connection = DBUtil.getConnection();
// 拼接sql语句 insert into role_menu (rid,mid) values(?,?),(?,?)...(?,?)
StringBuilder stringBuilder = new StringBuilder();
// 拼接固定的内容
stringBuilder.append("insert into role_menu (rid,mid) values ");
for (int i = 0; i < menuIds.length; i++) {
stringBuilder.append("(?,?)");
if (i == menuIds.length - 1) break; // 最后一个(?,?)没有 ,
stringBuilder.append(",");
}
// 获取预编译对象
PreparedStatement preparedStatement = connection.prepareStatement(stringBuilder.toString());
// 定义变量,记录占位符?的位置
int count = 1;
// 给?赋值
for (String menuId : menuIds) {
preparedStatement.setLong(count++,rid);
preparedStatement.setLong(count++,Long.parseLong(menuId));
}
// 执行sql语句
int row = preparedStatement.executeUpdate();
// 释放资源
DBUtil.release(connection,preparedStatement);
return row;
}
}
4 MD5加密
在JDK中实现加密 BASE64(可逆的) 加密 BASE64.Encoder 解密 BASE64.Decoder 信息摘要算法 MD5 不可逆的
-
BASE64
public static void main(String[] args) {
// Base64.Encoder encoder = Base64.getEncoder();
// String str = encoder.encodeToString("123456".getBytes());
// System.out.println(str);
Base64.Decoder decoder = Base64.getDecoder();
byte[] bytes = decoder.decode("MTIzNDU2");
System.out.println(new String(bytes));
}
-
MD5
package cn.javasm.util;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
private static final String SALT = "ewgefefgt";
public static String encode(String str) throws NoSuchAlgorithmException {
//获取MD5对象
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
str += SALT;
messageDigest.update(str.getBytes());
// 进行加密 将每个字节转换成2个16进制的字符
byte[] digest = messageDigest.digest();
BigInteger bigInteger = new BigInteger(1,digest);
String string = bigInteger.toString(16);
System.out.println(string);
return new String(digest);
}
}
5 DCL
事务是逻辑上的一组操作,组成这组操作的单元要么同时成功,要么同时失败
准备工作
create table account( id int PRIMARY KEY auto_increment, name varchar(255), money double ); insert into account values(null,'zs',1000); insert into account values(null,'ls',1000); insert into account values(null,'ww',1000);
5.1 MySql进行事务管理
-
手动开启事务
start transaction; 开启事务 commit; 提交事务 rollback; 回滚事务
5.2 事务的特性和隔离级别[面试题]
5.2.1 事务的特性
-
原子性:原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
eg: zs给ls转100 要么都成功 zs 900 ls 1100 要么都失败 zs 1000 ls 1000
-
一致性:事务前后数据的完整性要保持一致
eg: zs 1000 ls 1000 总共2000 成功 zs 900 ls 1100 总共2000 失败 zs 1000 ls 1000 总共2000
-
持久性:指一个事务一旦被提交,它对数据库的数据改动是永久性的,接下来即使数据库发生故障也不应该对结果有任何影响
-
隔离性: 事务的隔离性指多个用户并发操作数据库时,一个用户的事务不能被其他用户的事务所干扰。多个并发事务之间的数据要相互隔离。
5.2.2 没有隔离性会引发的问题
事务在理想状态下,所有的事务之间要保持隔离,互不影响。因为多个并发操作,多个用户同时访问数据,有可能引发数据安全问题。
| 可能出现的问题 | 含义 |
|---|---|
| 脏读 | 一个事务读取到了另一个事务中尚未提交的数据 |
| 不可重复读 | 一个事务中两次读取到数据内容不一致,这是事务update时引发的问题 |
| 幻读 | 一个事务中两次读取到的数据数量不一致,这是insert或者delete引发的问题 |
5.2.3 事务的隔离级别
| 级别 | 名字 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库的默认级别 |
|---|---|---|---|---|---|---|
| 1 | 读未提交 | read uncommitted | 会 | 会 | 会 | |
| 2 | 读已提交 | read committed | 不会 | 会 | 会 | oracle |
| 3 | 可重复读 | repeatable read | 不会 | 不会 | 会 | mysql |
| 4 | 串行化 | serializable | 不会 | 不会 | 不会 |
隔离级别越高,安全性越高,性能效率越差
-
查看当前事务的隔离级别
select @@transaction_isolation;
-
设置当前数据库事务的隔离级别(临时设置)
set session transaction isolation level 隔离级别
5.2.4 演示脏读
一个事务读取到了另一个事务尚未提交的数据 read uncommitted
-
开启AB窗口
-
设置A窗口的隔离级别为read uncommitted
set session transaction isolation level read uncommitted;
-
AB窗口都开启事务
-
在B窗口中把zs的钱减少100,事务不要提交
-
在A窗口中查询账户,发现账户内容改动,出现了脏读
5.2.5 演示不可重复读
不可重复读就是在一个事务里面,同一条sql语句,两次查询的结果不一致
-
开启AB窗口
-
设置A窗口的隔离级别时 读已提交(解决脏读)
set session transaction isolation level read committed;
-
AB窗口都开启事务
-
在B中zs金额较少100,不提交事务
-
在A中查看(避免了脏读)
-
在B中提交事务
-
在A中查看,发现数据改变,出现了不可重复读
5.2.6 演示隔离级别串行化
-
开启AB窗口
-
设置A窗口的隔离级别是串行化
set session transaction isolation level serializable;
-
AB窗口都开启事务
-
在B中zs金额减少100,不提交事务
-
在A中查询,会发现A中在等待B中提交事务
-
在B中提交事务
-
在A中查看,可以看到已经提交过的内容
5.2.7 代码级别使用事务
// 开启事务
connection.setAutoCommit(false);
// 提交事务
connection.commit();
// 回滚事务
connection.rollback();
使用的时候注意,连接要保证是同一个,否则会回滚失败
public class RoleServiceImpl implements RoleService {
@Override
public int insertRoleService(Role role, String[] menuIdArray) {
// 编写业务逻辑 密码加密 事务控制 日志记录 权限检查...
// 添加角色是一个业务逻辑 分为添加角色表和中间表
// 获取连接
Connection connection = DBUtil.getConnection();
RoleDao roleDao = new RoleDaoImpl(connection);
try {
// 手动开启事务
connection.setAutoCommit(false);
// 添加角色表
Long rid = roleDao.insertRole(role);
// int i = 1 / 0;
// 添加中间表
int row = roleDao.insertRoleAndMenu(rid, menuIdArray);
// 提交事务
connection.commit();
return row;
} catch (Exception e) {
try {
// 回滚事务
connection.rollback();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
throw new RuntimeException(e);
}finally {
// 释放资源
DBUtil.release(connection);
}
}
}
6 连接池
6.1 连接池入门版本
-
自定义连接池
public class MyDataSource1 {
// 连接池
private static LinkedList<Connection> pool;
static {
// 静态代码块
// 创建连接池
pool = new LinkedList<>();
for (int i = 0; i < 5; i++) {
pool.add(DBUtil.getConnection());
}
}
/**
* 提供连接
*/
public Connection getConnection(){
Connection connection = pool.removeFirst();
return connection;
}
/**
* 归还连接
*/
public void addBack(Connection connection){
pool.addLast(connection);
}
}
-
使用


6.2 连接池进阶版本
在上面的版本中,我们定义的方法是getConnection()获取连接,那么其他同学也可以使用getAbc()...来获取连接。
为了规范开发,sun公司提供了一套接口DataSource来定好方法的命名,各大厂商都实现了这套规范
-
自定义连接池
public class MyDataSource2 implements DataSource {
private static LinkedList<Connection> pool;
static {
pool = new LinkedList<>();
for (int i = 0; i < 5; i++) {
pool.add(DBUtil.getConnection());
}
}
/**
* 归还连接
*/
public void goHome(Connection connection){
pool.addLast(connection);
}
/**
* 获取连接
* @return
* @throws SQLException
*/
@Override
public Connection getConnection() throws SQLException {
return pool.removeFirst();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
-
使用


6.3 连接池最终版本
上面的连接池,归还的方法是goHome,依然没有规范。
能不能让连接池自带的close方法不再是关闭连接,而是归还连接?
我们的需求是要增强某一个类的某一些方法,可以考虑:继承重写,装饰者设计模式,代理设计模式
装饰者设计模式的作用:改写已存在的类的某个方法,增强方法的逻辑
使用装饰者设计模式需要满足的条件:
-
增强类和被增强类实现的是同一个接口,或者有共同的父类
-
增强类里面要拿到被增强类的引用
public class TestDemo3 {
public static void main(String[] args) {
Car car = new BYD(new BMW());
car.run();
car.stop();
}
}
// 被增强类和增强类都实现的接口
interface Car{
void run();
void stop();
}
// 被增强类
class BMW implements Car{
@Override
public void run() {
System.out.println("百米加速10秒~");
}
@Override
public void stop() {
System.out.println("skr~");
}
}
// 增强类
class BYD implements Car{
private Car car;
public BYD(Car car){
this.car = car;
}
@Override
public void run() {
System.out.println("百米突破3秒~");
}
@Override
public void stop() {
car.stop();
}
}
-
自定义MyConnection 增强类
// 增强类
public class MyConnection implements Connection {
private Connection connection;// 被增强类的引用
private LinkedList<Connection> pool;//连接池
public MyConnection(Connection connection, LinkedList<Connection> pool) {
this.connection = connection;
this.pool = pool;
}
// 改写close的逻辑,变成归还
@Override
public void close() throws SQLException {
pool.addLast(connection);
System.out.println("归还了" + connection);
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return connection.prepareStatement(sql);
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
connection.setAutoCommit(autoCommit);
}
@Override
public boolean getAutoCommit() throws SQLException {
return false;
}
@Override
public void commit() throws SQLException {
connection.commit();
}
@Override
public void rollback() throws SQLException {
connection.rollback();
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return connection.prepareStatement(sql,autoGeneratedKeys);
}
-
自定义连接池
public class MyDataSource3 implements DataSource {
private static LinkedList<Connection> pool;
static {
pool = new LinkedList<>();
for (int i = 0; i < 5; i++) {
pool.add(DBUtil.getConnection());
}
}
@Override
public Connection getConnection() throws SQLException {
Connection connection = pool.removeFirst();
System.out.println("获取了" + connection);
MyConnection myConnection = new MyConnection(connection,pool);
return myConnection;
}
-
使用



被折叠的 条评论
为什么被折叠?



