事务

一个SESSION所进行的所有更新操作要me一起成功,要么一起失败。

A向B转账这个流程中如果出现问题,事务可以让数据恢复成原来一样【A账户的钱没变,B账户的钱也没变】。

        //JDBC默认情况下是关闭事务的
        Connection connection=null;
        PreparedStatement preparedStatement=null;

        try {
            connection=DBUtils.getConnection();
            //A账户增加20
            String sql1="update userinfo set money=money+20 where userid=1";
            preparedStatement=connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();
            //模拟出现问题
            int i=30/0;
            //B账户减少20
            String sql2="update userinfo set money=money-20 where userid=2";
            preparedStatement=connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtils.close(null,preparedStatement,connection);
        }

结果上面代码导致A账户增加20,而B账户没有减少。上述问题可以通过事务解决。

        Connection connection=null;
        PreparedStatement preparedStatement=null;

        try {
            connection=DBUtils.getConnection();
            //开启事务,对数据的操作就不会立即生效
            connection.setAutoCommit(false);
            //A账户增加20
            String sql1="update userinfo set money=money+20 where userid=1";
            preparedStatement=connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();
            int i=30/0;
            //B账户减去20
            String sql2="update userinfo set money=money-20 where userid=2";
            preparedStatement=connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();
            //程序执行到这里,没有异常,就提交数据
            connection.commit();
            //关闭事务【自动提交】
            connection.setAutoCommit(true);
        } catch (Exception e) {
            try {
                //有异常 执行这里,事务回滚
                connection.rollback();
                //关闭事务,自动提交
                connection.setAutoCommit(true);
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            DBUtils.close(null,preparedStatement,connection);
        }

事务的隔离级别

数据库定义了4个隔离级别:

  1. Serializable【可避免脏读,不可重复读,虚读】
  2. Repeatable read 【可避免脏读,不可重复读】
  3. Read committed 【可避免脏读】
  4. Read uncommitted 【级别最低,什么都避免不了】

分别对应Connection类中的4个常量

  1. TRANSACTION_SERIALIZABLE
  2. TRANSACTION_REPEATABLE_READ
  3. TRANSACTION_READ_COMMITTED
  4. TRANSACTION_REAND_UNCOMMITTED

脏读:一个事务读取到另外一个事务未提交的数据

A向B转账,A执行了转账语句,但是A还没有提交事务,B读取数据,发现自己账户钱变多了。B跟A说,我已经收到钱了。A回滚事务【rollback】,等到B再查看账户的钱时,发现钱并没有多。

不可重复读:一个事务读取到另外一个事务已经提交的数据,也就是一个事务可以看到其他事务所做的修改。

A查询数据库得到数据,B去修改数据库的数据,导致A多次查询数据库的结果都不一样【危害:A每次查询的结果都是受B的影响的,那么A查询出来的信息就没有意义了】

虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

和不可重复读类似,但虚读(幻读)会读到其他事务的插入的数据,导致前后读取不一致。

总结:脏读是不可容忍的,不可重复读和虚读在一定的情况下是可以的【做统计的肯定就不行】

元数据

元数据就是数据库,表,列的定义信息。

即使写了一个简单工具类,代码还是冗余。对于增删改而言,只有SQL和参数是不同的,可以将这些不同的代码抽象成一个方法;对于查询而言,不同的实体查询出来的结果集不一样的。这就要使用元数据获取结果集的信息,才能对结果集进行操作。

  • ParameterMetaData    --参数的元数据
  • ResultSetMetaData     --结果集的元数据
  • DataBaseMetaData    --数据库的元数据

改造JDBC工具类

对数据库的增删改查都要连接数据库,关闭资源,获取PreparedStatement对象,获取Connection对象此类的操作,这样的代码重复率是极高的,所以对工具类进行增强。

增删查

    public static void update(String sql,Object[] objects){
         Connection connection=null;
         PreparedStatement preparedStatement=null;
         ResultSet resultSet=null;

        try {
            connection=getConnection();
            preparedStatement=connection.prepareStatement(sql);
            //添加参数
            for(int i=0;objects!=null&&i<objects.length;i++){
                preparedStatement.setObject(i+1,objects[i]);
            }
            //执行sql
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
           //释放资源
           close(resultSet,preparedStatement,connection);
        }
    }

查询

public static Object query(String sql,Object[] paremeters,ResultSetHandler rsh){
      Connection connection=null;
      PreparedStatement preparedStatement=null;
      ResultSet resultSet=null;
      try{
            connection=getConnection();
            preparedStatement=connection.prepareStatement(sql);
            for(int i=0;i<paremeters.length;i++){
                  preparedStatement.setObject(i+1,paremeters[i]);
            }
            resultSet=preparedStatement.executeQuery();
            return rsh.handler(resultSet);
      }catch(SQLException e){
            e.printStackTrace();
      }finally{
            close(resultSet,preparedStatement,connection);
      }
      return null;
}

接口

public Interface ResultSetHandler{
      Object handler(ResultSet rs);
}

实现类

public Class BeanHandler implements ResultHandler{
       private Class clazz;

       public BeanHandler(Class clazz){
                this.clazz=clazz;
       }

       public Object handler(ResultSet rs){
        try {
            List list = new ArrayList();
            while (resultSet.next()) {
                Object bean = clazz.newInstance();
                ResultSetMetaData metaData = resultSet.getMetaData();
                for (int i = 0; i < metaData.getColumnCount(); i++) {
                    String columnName = metaData.getColumnName(i + 1);
                    String columnData = resultSet.getString(i + 1);
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(bean,columnData);
                }
                list.add(bean);
            }
            return  list;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return  null;
       }
}

调用时代码

        String sql="select * from userinfo where usersex=? and userage>?";
        Object[] objects={"男",30};
        BeanHandler beanHandler=new BeanHandler(UserInfo.class);
        List<UserInfo> userInfos = (List<UserInfo>)DBUtils.query(sql, objects, beanHandler);

 

 posted on 2019-06-02 11:27  会飞的金鱼  阅读(93)  评论(0)    收藏  举报