您的位置:首页 > 其它

JDBC基础学习笔记_04_jdbc事务处理

2015-11-03 17:05 676 查看
一.什么是事务呢?

事务是并发控制的基本单位,如果在同一时间由多个用户同时对数据库进行操作,数据库数据会紊乱,我们要对这种并发行为,进行控制。

举个例子: 银行的转账功能,出账和进账,要么都执行,要么都不执行,我们将其看成一个事务。

我们编程时,可以将事务看成一组sql语句,其结果作为一个整体永久的修改数据库,或者同时放弃对数据库的修改。

二.事务的四个特征:

1. 原子性: 事务中包含的操作都被看做是一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。

2.一致性: 事务开始之前,事务结束之后,数据库都处于一致性状态,完整性约束没有破坏。

3. 隔离性: 事务之间是独立的,一个事务不能影响其他事务。

4. 持久性: 事务完成之后,对系统影响是永久的,对数据库的操作结果也是永久的。

三. 事务的sql语句

1.开始事务 : BEGIN TRANSACTION

2. 提交事务 : COMMIT TRANSACTION

3. 回滚事务: ROLLBACK TRANSACTION

四. 我们做一个错误的实例,之前我们有两张表,一张用户表,一张地址表,我们用两个方法将maik这个人,插入到两个表中,在地址表中制造异常信息。

package com.langzimingjian.com;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class TransactionTest {
/**
* 连接数据库,返回Connection对象
* @return 返回的Connection对象
*/
public static Connection getConnection(){
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp_bd","root", "");

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connection;

}
/**
* 向用户表插入数据
*/
public static void insertUserTable(){
Connection coneConnection = getConnection();
String insertString = "insert into tbl_user(id,name,password,email) values(?,?,?,?)";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;

try {
preparedStatement = coneConnection.prepareStatement(insertString);
preparedStatement.setInt(1,20);
preparedStatement.setString(2,"maik");
preparedStatement.setString(3,"12345678910");
preparedStatement.setString(4,"maik@qq.com");
int count = preparedStatement.executeUpdate();
System.out.println("成功插入" + count + "条数据");
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(coneConnection != null){
coneConnection.close();
}
if(preparedStatement!= null){
preparedStatement.close();
}
if(resultSet!= null){
resultSet.close();
}
} catch (Exception e2) {
// TODO: handle exception
}
}
}
/**
* 向地址表中插入数据
*/
public static void insertAddressTable(){
Connection connection = getConnection();
PreparedStatement preparedStatement = null;
try {
String insertString = "insert into tbl_address(id,city,country,user_id)values(?,?,?,?)";
preparedStatement = connection.prepareStatement(insertString);
/*	因为地址表中已经有主键为1了,所以插入地址表的时候会抛出异常*/
preparedStatement.setInt(1, 1);
preparedStatement.setString(2, "三亚");
preparedStatement.setString(3, "中国");
preparedStatement.setInt(4, 20);
int count = preparedStatement.executeUpdate();
System.out.println("成功插入" + count + "条语句到地址表");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
try {
if(connection != null){connection.close();}
if(preparedStatement != null){preparedStatement.close();}
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
public static void main(String[] args) {
insertUserTable();
insertAddressTable();
}
}
注意第七十行。运行结果







我们看到user表更改了,但是对应的地址表没有更改,数据不一致,这是个很严重的问题,我们应该运用事务来解决它,即地址表不能更改的话,user表也不能改!

五. 我们在四的基础上修改代码,代码如下:

先放上关于Connection.setAutoCommit的使用:http://blog.csdn.net/xiayimiaokuaile/article/details/6422032

(设定setAutoCommit(false)没有在catch中进行Connection的rollBack操作,操作的表就会被锁住,造成数据库死锁):

代码中的方法都进行了修改:

package com.langzimingjian.com;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class TransactionTest {
/**
* 连接数据库,返回Connection对象
* @return 返回的Connection对象
*/
public static Connection getConnection(){
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp_bd","root", "");

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connection;

}
/**
* 向用户表插入数据
*/
public static void insertUserTable(Connection coneConnection) throws Exception{
String insertString = "insert into tbl_user(id,name,password,email) values(?,?,?,?)";
PreparedStatement preparedStatement = null;

preparedStatement = coneConnection.prepareStatement(insertString);
preparedStatement.setInt(1,20);
preparedStatement.setString(2,"maik");
preparedStatement.setString(3,"12345678910");
preparedStatement.setString(4,"maik@qq.com");
int count = preparedStatement.executeUpdate();
System.out.println("成功插入" + count + "条数据");

}
/**
* 向地址表中插入数据
*/
public static void insertAddressTable(Connection connection) throws Exception{
PreparedStatement preparedStatement = null;
String insertString = "insert into tbl_address(id,city,country,user_id)values(?,?,?,?)";
preparedStatement = connection.prepareStatement(insertString);
/*	因为地址表中已经有主键为1了,所以插入地址表的时候会抛出异常*/
preparedStatement.setInt(1, 1);
preparedStatement.setString(2, "三亚");
preparedStatement.setString(3, "中国");
preparedStatement.setInt(4, 20);
int count = preparedStatement.executeUpdate();
System.out.println("成功插入" + count + "条语句到地址表");

}
public static void main(String[] args) {
Connection connection = null;
try {
connection = getConnection();
//在這裡設置為false,如果下面對表操作出現異常,最終不會修改數據庫
connection.setAutoCommit(false);
insertUserTable(connection);
insertAddressTable(connection);
//提交事務
connection.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("======捕捉到sql異常=====");

e.printStackTrace();
try {
//這裡是重點:(设定setAutoCommit(false)没有在catch中进行Connection的rollBack操作,操作的表就会被锁住,造成数据库死锁):
connection.rollback();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}finally{
try {
if(connection!= null){connection.close();}
} catch (Exception e3) {
// TODO: handle exception
e3.printStackTrace();
}
}
}
}
}
运行结果:







我们看到,并没有插入数据,事务功能成功~~~记得之前说的注意,一定要在catch中回滚。!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: