JAVA第一阶段结束喽后天更新第二阶段至于明天当然是练习时间回顾一下之前学的太良心了
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中
@Overridepublic 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;} @Overridepublic 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
@Overridepublic List<User> queryUserByParamAndPage(SearchParamVo searchParamVo, int page, int pageSize) {// 获取连接Connection connection = DBUtil.getConnection();// 拼接sql语句StringBuilder stringBuilder = new StringBuilder();// 拼接sql语句前面固定的内容stringBuilder.append("select * from user");// 动态拼接sqlappendSql(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;}@Overridepublic 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){// 如果有条件参数,删除掉最后一个多余的ANDstringBuilder.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中实现方法
@Overridepublic 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中
@Overridepublic 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)");// 获取用户输入的菜单的idString menuIdStr = scanner.next();String[] menuIds = menuIdStr.split(",");// 新增角色Role role = new Role().setRoleName(newRoleName).setRoleDesc(newRoleDesc);RoleDao roleDao = new RoleDaoImpl();// 添加角色后获取新增角色的idLong 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 {@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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 {@Overridepublic 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*/@Overridepublic Connection getConnection() throws SQLException {return pool.removeFirst();}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic 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{@Overridepublic void run() {System.out.println("百米加速10秒~");}@Overridepublic void stop() {System.out.println("skr~");} } // 增强类 class BYD implements Car{private Car car;public BYD(Car car){this.car = car;}@Overridepublic void run() {System.out.println("百米突破3秒~");}@Overridepublic 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的逻辑,变成归还@Overridepublic void close() throws SQLException {pool.addLast(connection);System.out.println("归还了" + connection);}@Overridepublic PreparedStatement prepareStatement(String sql) throws SQLException {return connection.prepareStatement(sql);}@Overridepublic void setAutoCommit(boolean autoCommit) throws SQLException {connection.setAutoCommit(autoCommit);}@Overridepublic boolean getAutoCommit() throws SQLException {return false;}@Overridepublic void commit() throws SQLException {connection.commit();}@Overridepublic void rollback() throws SQLException {connection.rollback();}@Overridepublic 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());}}@Overridepublic Connection getConnection() throws SQLException {Connection connection = pool.removeFirst();System.out.println("获取了" + connection);MyConnection myConnection = new MyConnection(connection,pool);return myConnection;}
使用