1. 程式人生 > 其它 >Spring處理資料池的事務回滾

Spring處理資料池的事務回滾

為什麼使用事務處理?

  在我們進行操作連表操作時,當我們在資料訪問層處理資料庫時,若是有一方有錯誤的地方。按理來說我們是不希望另一張表插入資料。

這時就就需要我們在我們業務邏輯層去進行操作對事務進行出來,來實現一方錯都不能實現對資料的操作。

  (一)通常情況下:

  1、我們在da層的實現層中手動加一出錯誤(int i=1/0):

  

@Repository("userDao")
//@Scope("singleton")
public class UserDaoImpl implements UserDao {

@Resource(name = "dataSource")
private DataSource dataSource;

@Resource
private TManager tManager;

public void insert(User user) throws SQLException {
// 正常情況
Connection connection = dataSource.getConnection();
// 使用事務回滾
// Connection connection = tManager.getConnection();
System.out.println(connection);
PreparedStatement statement = connection.prepareStatement("insert into spring_res(name,password) values (?,?)");
statement.setString(1,user.getName());
statement.setString(2,user.getPassword());
statement.executeUpdate();

}

public void insert(SpringCha springCha) throws SQLException {
// 正常情況
Connection connection = dataSource.getConnection();
// 使用事務回滾
// Connection connection = tManager.getConnection();
System.out.println(connection);
PreparedStatement statement = connection.prepareStatement("insert into spring_cha(habit,hobby) values (?,?)");
statement.setString(1,springCha.getHabit());
statement.setString(2,springCha.getHobby());
int i=1/0;
statement.executeUpdate();

}
}

  2、而在業務邏輯層:

@Service("userService")
public class UserServiceImpl implements UserService {


@Resource(name = "userDao")//這個相當於上面兩個的
private UserDao userDao;


@Resource
private TManager tManager;
public void inserts(User user) throws SQLException {
// try {
// tManager.closeCommit();
userDao.insert(user);
SpringCha springCha = new SpringCha();
springCha.setHabit("先吃再睡");
springCha.setHobby("吃喝睡");
userDao.insert(springCha);
// tManager.commit();
// } catch (SQLException e) {
// tManager.rollBack();
// e.printStackTrace();
// }
}
}

在操作中註釋的是後續寫的事務管理器用來解決上面的錯誤帶來的問題

  3、在使用SpringJunit來寫一個測試類

 @Resource
private UserService userService;
// @Resource
// private User user;
@Test
public void testInsert() throws SQLException {
User user = new User();
user.setName("楓");
user.setPassword("201619");
userService.inserts(user);
}

在執行測試用例後,會出現正常的報錯(i=1/0),但是資料庫中兩張表,一張是把資料插入的另一張沒有。

  (二)進行事務處理

  1、先編寫一個事務控制器,來處理上面的問題

@Component
public class TManager {

@Resource
private DataSource dataSource;

// 用於建立連線得ThreadLocal
private ThreadLocal<Connection> local= new ThreadLocal<Connection>();

/**
* 基於Druid連線池獲取連線
* @return
* @throws SQLException
*/
public Connection getConnection() throws SQLException {
// dao方法在獲取連線的時候判斷是否存在連線
if (local.get()!=null){
return local.get();
}
// 建立新的連線
Connection connection = dataSource.getConnection();
// 建立新的連線可能還被使用,所以把新的連線進行儲存
local.set(connection);
return connection;
}

/**
*
* @throws SQLException
*/
public void closeCommit() throws SQLException {
getConnection().setAutoCommit(false);
}
/**
*提交事務
* @throws SQLException
*/
public void commit() throws SQLException {
getConnection().commit();
}

/**
*回滾事務
* @throws SQLException
*/
public void rollBack() throws SQLException {
getConnection().rollback();
}

}

  2、在資料訪問層不改動下去業務邏輯層對其進行改動處理

try {
tManager.closeCommit();
userDao.insert(user);
SpringCha springCha = new SpringCha();
springCha.setHabit("先吃再睡");
springCha.setHobby("吃喝睡");
userDao.insert(springCha);
tManager.commit();
} catch (SQLException e) {
tManager.rollBack();
e.printStackTrace();
}

  3、可以直接使用剛的測試用例;

總結:

一般來說我們在使用資料來源進行操作資料庫時,一般是自動進行提交事務,當我想使用手動進行提交時,需要使用Connection.setAutoCommit(false) 可以阻止自動提交 。

java使用事務非常簡單,首先呼叫conn.setAutoCommit(boolean b)方法,傳入一個false,這樣將不會自動提交,而需要使用conn.commit()方法,手動提交事務,當然只有在確認兩個步驟都沒有出錯的情況下,才能提交,這樣才能保證整個操作的完整性,一旦出錯,使用conn.rollback()方法,回滾事務,這樣的話,整個事務都將不被提交。那麼如何判斷有沒有出錯呢,非常簡單,執行資料庫操作的方法,都會丟擲java.sql.SQLException,所以需要使用try……catch語句塊捕獲異常,在catch塊中,使用conn.rollback()回滾事務即可。

       在資料庫呼叫的javabeanconn.setAutoCommit()的功能是每執行一條SQL語句,就作為一次事務提交。但一般在專案中很有可能需要執行多條SQL語句作為一個事務。若有一個執行不成功,就會rollback();

 

一般來講,大家對資料庫中的表單,主要是增、刪、改、查 這四個操作,如果你的程式當中,遇到一次業務邏輯需要兩次或兩次以上的對相同資料表的增刪改操作,那麼,為了資料的一致性,(或者具體說,在你的一次業務邏輯的處理過程中,其他(執行緒或程式或業務處理)的對相同資料的相同兩次查詢所得結果相同。)我們會利用資料庫的事務操作,將一次業務邏輯所包含的所有操作封裝在一個事務裡,一次將多個操作進行提交。

connsetAutoCommit方法是指,在事務當中,是否執行一條語句就自動提交一次。

想在一個事務裡進行多個操作。就必然將setAutoCommit的引數設定成false,在多個操作的最後呼叫conn.commit()方法,進行手動提交

 

setAutoCommit(引數))引數:truefalse

 

假設如下:

1 資料庫一個表格有50條記錄

2 你設定引數為false

則在你執行整個查詢SQL期間,一直是沒有事務的,那麼如果你的查詢用到了一些函式,這些函式包含了多個查詢語句,那麼有可能會出現不一致的情況。

也就是說,函式、儲存過程等,他們都將執行在非事務的環境下。

而你設定為true,則沒有任何問題了,讀一致性將保證不會出現問題。