4天贯通JDBC技术六、数据库事务(重点)

1.事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。

 

2.事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。

当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;

要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。

 

// 以下的两个操作共同构成一个数据库事务。但是在两个操作之间可能出现异常问题。

// 原则上,一旦出现问题,就需要将之前的操作“回滚”!需要对如下的操作进行完善。

@Test

public void testUpdate() {

String sql1 = "update user_table set balance = balance - 100 where user = ?";

update(sql1, "AA");

 

System.out.println(10 / 0);

 

String sql2 = "update user_table set balance = balance + 100 where user = ?";

update(sql2, "BB");

}

 

 

3.考虑到数据库事务的话,我们又将原来使用PreparedStatement重构的Statement的增删改和查的操作,再升级。

// 实现一个通用的UPDATE INSERT DELETE的操作的方法(version 3.0)

public void update(Connection conn,String sql, Object... args) {

PreparedStatement ps = null;

try {

ps = conn.prepareStatement(sql);

for (int i = 0; i < args.length; i++) {

ps.setObject(i + 1, args[i]);

}

 

ps.execute();

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.close(null, ps, null);

}

}

 

// 实现一个通用的查询操作,返回一个对象(version 3.0)

public <T> T getInstance(Connection conn,String sql, Class<T> clazz, Object... args) {

PreparedStatement ps = null;

ResultSet rs = null;

try {

 

ps = conn.prepareStatement(sql);

// 填充占位符

for (int i = 0; i < args.length; i++) {

ps.setObject(i + 1, args[i]);

}

// 4.执行并返回ResultSet的对象

rs = ps.executeQuery();

 

if (rs.next()) {

// 5.创建T的对象

T t = clazz.newInstance();

// 6.将结果集中的列值作为T的对象的属性,给予赋值

ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();

for (int i = 0; i < columnCount; i++) {

Object columnVal = rs.getObject(i + 1);

String columnLabel = rsmd.getColumnLabel(i + 1);

PropertyUtils.setProperty(t, columnLabel, columnVal);

}

return t;

}

 

} catch (Exception e) {

e.printStackTrace();

} finally {

// 7.关闭相应的操作

JDBCUtils.close(rs, ps, null);

}

return null;

}

// 实现一个通用的查询操作,返回一个对象的集合(version 3.0)

public <T> List<T> getForList(Connection conn,String sql,Class<T> clazz,Object ... args){

PreparedStatement ps = null;

ResultSet rs = null;

List<T> list = new ArrayList<T>();

try{

ps = conn.prepareStatement(sql);

for(int i = 0;i < args.length;i++){

ps.setObject(i + 1, args[i]);

}

rs = ps.executeQuery();

ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();

while(rs.next()){

T t = clazz.newInstance();

for(int i = 0;i < columnCount;i++){

Object columnVal = rs.getObject(i + 1);

String columnLabel = rsmd.getColumnLabel(i + 1);

PropertyUtils.setProperty(t, columnLabel, columnVal);

}

list.add(t);

}

}catch(Exception e){

e.printStackTrace();

}finally{

JDBCUtils.close(rs, ps, null);

}

return list;

}

 

//考虑到数据库事务,通过java程序对数据库中表的操作的模板(掌握)

public void method(){

Connection conn = null;

try{

//1.获取数据库的连接(①conn = JDBCUtils.getConnection(); ②数据库连接池(开发者选择此))

//2.开启事务

conn.setAutoCommit(false);

//3.对数据库中表进行相应的操作(增、删、改、查)(①version 3.0 ②DBUtils工具类:update()  和query()方法)

//4.提交事务

conn.commit();

}catch(Exception e){

e.printStackTrace();

try{

//5.回滚事务

conn.rollback();

}catch(Exception e1){

e1.printStackTrace();

}

}finally{

//6.关闭数据库的连接(①自己实现数据库相应资源的关闭JDBCUtils.close(null,null,conn); ②使用DBUtils工具类的close()方法)

}

}

 

了解:

针对隔离性,我们提供了不同数据库处理的隔离级别,针对处理数据发生的问题(脏读、不可重复读、幻读)提供了多张隔离级别

隔离级别:(脏读是我们一定哟啊避免的,而不可重复读、幻读是允许存在的)

·