事务
一个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个隔离级别:
- Serializable【可避免脏读,不可重复读,虚读】
- Repeatable read 【可避免脏读,不可重复读】
- Read committed 【可避免脏读】
- Read uncommitted 【级别最低,什么都避免不了】
分别对应Connection类中的4个常量
- TRANSACTION_SERIALIZABLE
- TRANSACTION_REPEATABLE_READ
- TRANSACTION_READ_COMMITTED
- 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
浙公网安备 33010602011771号