java入门--------JDBC3(尚马day25) week6(4)

5. 自增id

新增新的老师,分配学生。

逆向生成实体类。 idea自带的数据源。

public class StudentDaoImpl implements StudentDao {
​
    private Connection connection;
    private PreparedStatement ps;
    private ResultSet rs;
    private String sql;
​
    @Override
    public List findStudentByPage(int page, int size) {
        connection = DBUtil.getConn();
        sql = "SELECT * FROM tb_student LIMIT ?,?";
        List studentList = new ArrayList<>(10);
        try {
            ps = connection.prepareStatement(sql);
            ps.setInt(1, (page - 1) * size);
            ps.setInt(2, size);
            rs = ps.executeQuery();
            while (rs.next()) {
                studentList.add(getStudentInstance(rs));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            DBUtil.close(connection,ps,rs);
        }
        return studentList;
    }
​
    private Student getStudentInstance(ResultSet rs) throws SQLException {
        Student student = new Student();
        student.setId(rs.getInt("id"));
        student.setStuName(rs.getString("stu_name"));
        student.setStuScore(rs.getDouble("stu_score"));
        student.setStuAge(rs.getInt("stu_age"));
        return null;
    }
}
​

老师关联学生:
 1. 分页查询学生表信息  tb_student
 2. 新增老师的记录  insert into tb_teacher (teacher_name) values (?)
 3. 新增中间表的记录-----> 维护老师和学生的关系
     insert into tb_teacher_student (tid,sid) values (?,?),(?,?)...(?,?);
  tid: 老师id  ---->刚刚新增的老师的id
  sid: 学生的id  idList

新增老师的dao

@Override
    public int addTeacher(Teacher teacher) {
        connection = DBUtil.getConn();
        sql = "INSERT INTO tb_teacher (teacher_name) VALUES (?)";
        int result = 0;
        try {
            ps = connection.prepareStatement(sql);
            ps.setString(1, teacher.getTeacherName());
            result = ps.executeUpdate();
​
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, ps, rs);
        }
        return result;
    }

更新中间表记录

//insert into tb_teacher_student (tid,sid) values (?,?),(?,?)...(?,?);
@Override
public int addTeacherAndStudent(int tid, Set ids) {
    connection = DBUtil.getConn();
    //动态拼接sql  ?
    StringBuilder builder = new StringBuilder("insert into tb_teacher_student (tid,sid) values ");
    int size = ids.size();
    for (int i = 1; i <= size; i++) {
        builder.append("(?,?)");
        if (i == size) {
            break;
        }
        builder.append(",");
    }
​
    int result = 0;
    //insert into tb_teacher_student (tid,sid) values (?,?),(?,?),(?,?)
    try {
        ps = connection.prepareStatement(builder.toString());
        //占位符赋值 第奇数个占位符肯定就是tid
        int count = 1;
        for (Integer id : ids) {
            ps.setInt(count++, tid);
            ps.setInt(count++, id);
        }
        //执行sql
        result = ps.executeUpdate();
​
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    } finally {
        DBUtil.close(connection, ps, rs);
    }
    return result;
}

修改新增老师的dao----> 获得自增的id

 @Override
    public int addTeacher(Teacher teacher) {
        connection = DBUtil.getConn();
        sql = "INSERT INTO tb_teacher (teacher_name) VALUES (?)";
        int autoId = 0;
        try {
            //在mysql里面 维护id自增?  SELECT LAST_INSERT_ID()  DQL----> 结果 rs
            //1.告诉mysql的服务  把id返回过来----> 将sql语句发送数据库的时候 就要告诉mysql服务器   Statement.RETURN_GENERATED_KEYS
            //2. 等价于mysql的服务在update之后  自动执行SELECT LAST_INSERT_ID()这条sql
​
            ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            ps.setString(1, teacher.getTeacherName());
            ps.executeUpdate();//执行sql语句 将数据持久化保存数据库
​
            //3.在update之后  获得自增的id的数据  由于是一条select语句 结果还是在rs里面
            rs = ps.getGeneratedKeys();
            if (rs.next()) {
                autoId = rs.getInt(1);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, ps, rs);
        }
        return autoId;
    }

问题:

//调用新增老师----> 调用2个方法  新增老师+新增中间表
//对于其他调用者而言 不是很优雅
//只需要调用1个新增老师的方法即可---->就能实现同时新增老师+新增中间表
//使用service
​
public class TeacherServiceImpl implements TeacherService {
​
    private static TeacherDao teacherDao = new TeacherDaoImpl();
​
    @Override
    public void addTeacher(Teacher teacher, Set idSet) {
        int tid = teacherDao.addTeacher(teacher);
        teacherDao.addTeacherAndStudent(tid, idSet);
        System.out.println("success");
    }
}

6. 事务 transaction

张三借给李四1000元。

update tb_student set money = money+1000 where id = 2;
update tb_student set money = money-1000 where id = 1;

是属于数据库的事务。 任意DBMs中存在事务特性。
// 概念: 就是一系列(DML)操作。这一系列操作 要么全部成功 要不全部失败。
//不可能出现部分成功 以及部分失败的情况  如果出现了 就是没有满足数据库事务的特性。
​
ACID:
 A: 原子性。一个不可分割的工作单位。要么全部成功 要不全部失败。 Atomic
 C: 一致性。 Consistency   事务开始前的数据  与事务提交之后的数据 必须要一致。
  张三给李四1000   3000   500
  提交之后:  2000 1500
      
 I: 隔离性。isolation  并发事务  多个客户端同时操作这一行记录 事务之间是相互隔离的。
   但是可能会对数据产生不同的影响。
  
 D:durability   持久性、  事务只要提交  数据可以持久化保存的。

6.0 DCL

-- 数据库里面事务一般都是默认自动提交的。
​
-- 查询mysql的事务是否是自动提交
-- SHOW VARIABLES like '%commit%';
-- OFF FALSE/ ON TRUE
-- 可以将事务自动改为手动操作
-- SET autocommit=1;
​
-- ok的数据还在虚拟表中   将事务自动提交给关闭了  只能手动提交事务
​
-- BEGIN; -- 手动开启事务
-- insert INTO demo (name,money) VALUES ('11',1000);
-- insert INTO demo (name,money) VALUES ('22',1000);
-- SELECT * FROM demo;
-- COMMIT;
-- ROLLBACK

6.1 代码级别实现事务

private static void zhuanZhang() {
        //张三-1000  1  3000
        //李四+1000  2  500
​
        //转账这一个功能: 里面涉及了2条dml
        //要么全部成功  要么全部失败
        //需要将这一系列操作 都放到一个“事务”中进行处理
        //最根本的原因在与: mysql服务里面 事务是自动提交的。
​
        //先查询 省略
​
​
        //调用这2个方法 应该在一个事务内执行
        //手动控制事务
        //在jdbc里面 默认调用mysql服务  事务也是自动提交的
        //jdbc: 事务操作与Connection  多个功能操作必须在同一个连接下
        //一个连接 就是一个事务
​
        //在正常开发中  dao层一般都不会有try...catch
        //一般都使用throws
        //获得连接对象
        Connection connection = DBUtil.getConn();
        try {
            //1. 将自动提交事务变为手动提交事务
            connection.setAutoCommit(false);
            StudentDao studentDao = new StudentDaoImpl(connection);
​
            studentDao.updateMoneyById(2, new BigDecimal("1500"));
            //System.out.println(3 / 0);
            studentDao.updateMoneyById(1, new BigDecimal("1000"));
            //2. 提交事务
            connection.commit();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
            //3. 出现任意异常   回滚事务--->回到原点
            try {
                connection.rollback();
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

@Override
public void updateMoneyById(int sid, BigDecimal money) throws Exception {
    sql = "update tb_student set money = ? where id = ?";
    ps = connection.prepareStatement(sql);
    ps.setBigDecimal(1, money);
    ps.setInt(2, sid);
    ps.executeUpdate();
}

 public StudentDaoImpl(Connection connection){
        this.connection = connection;
    }

开启事务 应该在service层开启

@Override
public void addTeacher(Teacher teacher, Set idSet) {
​
    //在service里面调用了多个dao
    //在service编写很多与业务相关的代码
    //程序运行期间 ----> 运行时异常
    //应该在一个事务内执行多个dao的方法
​
    Connection connection = DBUtil.getConn();
​
    try {
        //1. 将事务由自动提交改为手动提交
        connection.setAutoCommit(false);
        TeacherDao teacherDao = new TeacherDaoImpl(connection);
​
        int tid = teacherDao.addTeacher(teacher);//insert
        //System.out.println(3 / 0);//出现异常当前程序终止了
        teacherDao.addTeacherAndStudent(tid, idSet);//insert
        //2.提交事务
        connection.commit();
        System.out.println("新增老师成功");
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("新增老师失败");
        try {
            //3.回滚事务
            connection.rollback();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    } finally {
        try {
            connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
​
    //一个功能里面 执行多条DML语句  insert  update  delete
    //转账
    //张三给李四转账
}

6.2 隔离级别机制(了解)

并发的事务环境中,数据库事务在不同的隔离级别机制下 ,会对数据产生不同的影响。

1. 数据库里面 存在哪些数据库隔离级别机制?  mysql的隔离级别机制是什么?
  
   read uncommitted 读未提交(一个事务读到了另外一个事务未提交的数据)
   read committed 读已提交  oracle sqlserver 默认的机制
   repeatable read 可重复读  mysql 默认的机制
   SERIALIZABLE 串行化
    
2. 会对数据产生哪些影响? 该如何解决?
    不同的数据库隔离级别机制  产生影响是否一致?
    
    1. 脏读(事务A读到了事务b未提交的数据)
    2. 不可重复读(在一个事务里面 多次读取 先后读取到的数据是不一致的  update)
    3. 幻读(在一个事务里面 执行多次查询 出现了很多上一次查询里面没有的数据  insert)

脏读 不可重复读 幻读
read uncommitted y y y
read committed n y y
repeatable read n n y
SERIALIZABLE(表锁) n n n

7. 反射

8. DBUtils

9. 数据库连接池

你可能感兴趣的:(尚马java课堂笔记,java,linq,开发语言)