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中

@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;
    }
  • 使用

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值