詳解Java的Spring框架中的事務治理方法。本站提示廣大學習愛好者:(詳解Java的Spring框架中的事務治理方法)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解Java的Spring框架中的事務治理方法正文
數據庫事務是被看成單個任務單位的操作序列。這些操作要末全體完成或全體不勝利。事務治理是面向企業運用法式,以確保數據的完全性和分歧性RDBMS中的主要構成部門。事務的概念可以用上面的描寫為ACID四個症結屬性來描寫:
原子性: 一個事務應當被視為單個操作單位表現的操作的任一全部序列是勝利的或不勝利的。
分歧性: 這代表了數據庫的參照完全性,在桌等獨一主鍵的分歧性
隔離性: 能夠有許多事務處置雷同的數據集的同時,每一個事務都應由別人隔離,以避免數據破壞。
耐久性: 一旦事務完成,本次事務的成果必需作出永遠性的,不克不及從數據庫中刪除因體系毛病。
一個真實的RDBMS數據庫體系將包管一切的四個屬性為每一個事務。發表給應用SQL數據庫的事務的簡略不雅點以下:
應用begin transaction敕令開端事務。
應用SQL查詢履行各類刪除,更新或拔出操作。
假如一切的操作都勝利,那末履行提交,不然回滾一切操作。
Spring框架供給的分歧的底層事務治理API之上的籠統層。在Spring的事務支撐,旨在經由過程增長事務功效,的POJO供給EJB的替換品事務。 Spring支撐兩種編程式和聲明式事務治理。須要的EJB運用法式辦事器,但Spring事務治理,而不須要一個運用辦事器來完成。
部分與全局事務
部分事務是針對像一個JDBC銜接一個單一的事務性資本,而全局事務可以逾越像事務多個事務資本的散布式體系。
部分事務治理可以在一個集中式盤算情況下的運用法式的組件和資本都位於一個單一的網站是有效的,而事務治理只觸及一個零丁的機械上運轉的當地數據治理。部分事務更輕易完成。
全局事務治理,須要在散布在多個體系中的一切資本的散布式盤算情況。在這類情形下,事務治理既須要在處所和全局層面的任務要做。一個散布式或全局事務在多個體系上履行,其履行須要全局事務治理體系和一切相干體系的一切部分數據治理人員之間的調和。
編程與聲明
Spring支撐兩品種型的事務治理:
編程式事務治理
編程式事務治理方法許可您治理與編程的源代碼的贊助下事務。這就給了極年夜的靈巧性,但它難以保護。
在我們開端之前,它至多有兩個數據庫表上,我們可以在事務的贊助下履行各類CRUD操作。讓我們以Student表,它可以在MySQL數據庫中測試用上面的DDL創立:
CREATE TABLE Student( ID INT NOT NULL AUTO_INCREMENT, NAME VARCHAR(20) NOT NULL, AGE INT NOT NULL, PRIMARY KEY (ID) );
第二個表是Marks,我們將堅持標志為基於多年的先生。這裡SID是表表的外鍵。
CREATE TABLE Marks( SID INT NOT NULL, MARKS INT NOT NULL, YEAR INT NOT NULL );
讓我們應用PlatformTransactionManager直接完成編程的辦法來完成事務。要開端一個新的事務,須要有TransactionDefinition 恰當的事務屬性的一個實例。在這個例子中,我們將簡略地創立DefaultTransactionDefinition的實例應用默許的事務屬性。
一旦TransactionDefinition被創立,你可以經由過程挪用getTransaction()辦法,它前往的TransactionStatus對象的一個實例開端事務。TransactionStatus對象有助於跟蹤事務確當前狀況,最初,假如一切順遂,可使用提交(的PlatformTransactionManager的)辦法來提交事務,不然可使用rollback() 回滾完成操作。
如今我們編寫Spring JDBC運用法式,將完成Student和Marks表簡略的操作。
以下是數據拜訪對象接口文件StudentDAO.java的內容:
package com.yiibai; import java.util.List; import javax.sql.DataSource; public interface StudentDAO { /** * This is the method to be used to initialize * database resources ie. connection. */ public void setDataSource(DataSource ds); /** * This is the method to be used to create * a record in the Student and Marks tables. */ public void create(String name, Integer age, Integer marks, Integer year); /** * This is the method to be used to list down * all the records from the Student and Marks tables. */ public List<StudentMarks> listStudents(); }
以下是StudentMarks.java文件的內容:
package com.yiibai; public class StudentMarks { private Integer age; private String name; private Integer id; private Integer marks; private Integer year; private Integer sid; public void setAge(Integer age) { this.age = age; } public Integer getAge() { return age; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setId(Integer id) { this.id = id; } public Integer getId() { return id; } public void setMarks(Integer marks) { this.marks = marks; } public Integer getMarks() { return marks; } public void setYear(Integer year) { this.year = year; } public Integer getYear() { return year; } public void setSid(Integer sid) { this.sid = sid; } public Integer getSid() { return sid; } }
以下是StudentMarksMapper.java文件的內容:
package com.yiibai; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; public class StudentMarksMapper implements RowMapper<StudentMarks> { public StudentMarks mapRow(ResultSet rs, int rowNum) throws SQLException { StudentMarks studentMarks = new StudentMarks(); studentMarks.setId(rs.getInt("id")); studentMarks.setName(rs.getString("name")); studentMarks.setAge(rs.getInt("age")); studentMarks.setSid(rs.getInt("sid")); studentMarks.setMarks(rs.getInt("marks")); studentMarks.setYear(rs.getInt("year")); return studentMarks; } }
上面是完成類文件StudentJDBCTemplate.java的界說DAO接口StudentDAO:
package com.yiibai; import java.util.List; import javax.sql.DataSource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; public class StudentJDBCTemplate implements StudentDAO { private DataSource dataSource; private JdbcTemplate jdbcTemplateObject; private PlatformTransactionManager transactionManager; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; this.jdbcTemplateObject = new JdbcTemplate(dataSource); } public void setTransactionManager( PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } public void create(String name, Integer age, Integer marks, Integer year){ TransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); try { String SQL1 = "insert into Student (name, age) values (?, ?)"; jdbcTemplateObject.update( SQL1, name, age); // Get the latest student id to be used in Marks table String SQL2 = "select max(id) from Student"; int sid = jdbcTemplateObject.queryForInt( SQL2 ); String SQL3 = "insert into Marks(sid, marks, year) " + "values (?, ?, ?)"; jdbcTemplateObject.update( SQL3, sid, marks, year); System.out.println("Created Name = " + name + ", Age = " + age); transactionManager.commit(status); } catch (DataAccessException e) { System.out.println("Error in creating record, rolling back"); transactionManager.rollback(status); throw e; } return; } public List<StudentMarks> listStudents() { String SQL = "select * from Student, Marks where Student.id=Marks.sid"; List <StudentMarks> studentMarks = jdbcTemplateObject.query(SQL, new StudentMarksMapper()); return studentMarks; } }
如今讓我們挪動主運用法式文件MainApp.java,這是以下:
package com.yiibai; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.yiibai.StudentJDBCTemplate; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); StudentJDBCTemplate studentJDBCTemplate = (StudentJDBCTemplate)context.getBean("studentJDBCTemplate"); System.out.println("------Records creation--------" ); studentJDBCTemplate.create("Zara", 11, 99, 2010); studentJDBCTemplate.create("Nuha", 20, 97, 2010); studentJDBCTemplate.create("Ayan", 25, 100, 2011); System.out.println("------Listing all the records--------" ); List<StudentMarks> studentMarks = studentJDBCTemplate.listStudents(); for (StudentMarks record : studentMarks) { System.out.print("ID : " + record.getId() ); System.out.print(", Name : " + record.getName() ); System.out.print(", Marks : " + record.getMarks()); System.out.print(", Year : " + record.getYear()); System.out.println(", Age : " + record.getAge()); } } }
以下是設置裝備擺設文件beans.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd "> <!-- Initialization for data source --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/TEST"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <!-- Initialization for TransactionManager --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- Definition for studentJDBCTemplate bean --> <bean id="studentJDBCTemplate" class="com.yiibai.StudentJDBCTemplate"> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> </bean> </beans>
創立源代碼和bean設置裝備擺設文件完成後,讓我們運轉運用法式。假如一切順遂,這將打印以下信息:
------Records creation-------- Created Name = Zara, Age = 11 Created Name = Nuha, Age = 20 Created Name = Ayan, Age = 25 ------Listing all the records-------- ID : 1, Name : Zara, Marks : 99, Year : 2010, Age : 11 ID : 2, Name : Nuha, Marks : 97, Year : 2010, Age : 20 ID : 3, Name : Ayan, Marks : 100, Year : 2011, Age : 25
聲明式事務治理
聲明式事務治理的辦法可贊助您治理設置裝備擺設,而不是在源代碼中硬編碼的事務。這意味著,可以零丁從營業代碼事務治理。只用正文或基於XML設置裝備擺設來治理事務。bean的設置裝備擺設將指定的辦法是事務性。以下是聲明性與事務相干的步調:
我們應用<tx:advice/>標簽,這將創立我們界說了一個切入點婚配一切我們想做成事務,並援用個中的事務告訴辦法的事務並同時處置建議。
假如一個辦法的名字已被列入事務設置裝備擺設,然後創立看法,將挪用該辦法之前開端生意業務。
目的辦法將在一個try/ catch塊被履行。
假如辦法正常完成,AOP的建議提交事務勝利,不然履行回滾。
讓我們來看看為什麼上述步調的任務,但在我們開端之前,它至多有兩個數據庫表上,我們可以用生意業務的贊助下履行各類CRUD操作是很主要的。讓我們以Student表,它可以在MySQL數據庫中測試用上面的DDL創立:
CREATE TABLE Student( ID INT NOT NULL AUTO_INCREMENT, NAME VARCHAR(20) NOT NULL, AGE INT NOT NULL, PRIMARY KEY (ID) );
第二個表是Marks ,我們將堅持標志為基於多年的先生。這裡SID是表Student的外鍵。
CREATE TABLE Marks( SID INT NOT NULL, MARKS INT NOT NULL, YEAR INT NOT NULL );
異樣來看一下相照顧的例子。
以下是數據拜訪對象接口文件StudentDAO.java的內容:
package com.yiibai; import java.util.List; import javax.sql.DataSource; public interface StudentDAO { /** * This is the method to be used to initialize * database resources ie. connection. */ public void setDataSource(DataSource ds); /** * This is the method to be used to create * a record in the Student and Marks tables. */ public void create(String name, Integer age, Integer marks, Integer year); /** * This is the method to be used to list down * all the records from the Student and Marks tables. */ public List<StudentMarks> listStudents(); }
以下是StudentMarks.java文件的內容:
package com.yiibai; public class StudentMarks { private Integer age; private String name; private Integer id; private Integer marks; private Integer year; private Integer sid; public void setAge(Integer age) { this.age = age; } public Integer getAge() { return age; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setId(Integer id) { this.id = id; } public Integer getId() { return id; } public void setMarks(Integer marks) { this.marks = marks; } public Integer getMarks() { return marks; } public void setYear(Integer year) { this.year = year; } public Integer getYear() { return year; } public void setSid(Integer sid) { this.sid = sid; } public Integer getSid() { return sid; } }
以下是StudentMarksMapper.java文件的內容:
package com.yiibai; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; public class StudentMarksMapper implements RowMapper<StudentMarks> { public StudentMarks mapRow(ResultSet rs, int rowNum) throws SQLException { StudentMarks studentMarks = new StudentMarks(); studentMarks.setId(rs.getInt("id")); studentMarks.setName(rs.getString("name")); studentMarks.setAge(rs.getInt("age")); studentMarks.setSid(rs.getInt("sid")); studentMarks.setMarks(rs.getInt("marks")); studentMarks.setYear(rs.getInt("year")); return studentMarks; } }
上面是完成類文件StudentJDBCTemplate.java 的界說DAO接口StudentDAO:
package com.yiibai; import java.util.List; import javax.sql.DataSource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; public class StudentJDBCTemplate implements StudentDAO{ private JdbcTemplate jdbcTemplateObject; public void setDataSource(DataSource dataSource) { this.jdbcTemplateObject = new JdbcTemplate(dataSource); } public void create(String name, Integer age, Integer marks, Integer year){ try { String SQL1 = "insert into Student (name, age) values (?, ?)"; jdbcTemplateObject.update( SQL1, name, age); // Get the latest student id to be used in Marks table String SQL2 = "select max(id) from Student"; int sid = jdbcTemplateObject.queryForInt( SQL2 ); String SQL3 = "insert into Marks(sid, marks, year) " + "values (?, ?, ?)"; jdbcTemplateObject.update( SQL3, sid, marks, year); System.out.println("Created Name = " + name + ", Age = " + age); // to simulate the exception. throw new RuntimeException("simulate Error condition") ; } catch (DataAccessException e) { System.out.println("Error in creating record, rolling back"); throw e; } } public List<StudentMarks> listStudents() { String SQL = "select * from Student, Marks where Student.id=Marks.sid"; List <StudentMarks> studentMarks=jdbcTemplateObject.query(SQL, new StudentMarksMapper()); return studentMarks; } }
如今我們挪動主運用法式文件MainApp.java,以下:
package com.yiibai; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); StudentDAO studentJDBCTemplate = (StudentDAO)context.getBean("studentJDBCTemplate"); System.out.println("------Records creation--------" ); studentJDBCTemplate.create("Zara", 11, 99, 2010); studentJDBCTemplate.create("Nuha", 20, 97, 2010); studentJDBCTemplate.create("Ayan", 25, 100, 2011); System.out.println("------Listing all the records--------" ); List<StudentMarks> studentMarks = studentJDBCTemplate.listStudents(); for (StudentMarks record : studentMarks) { System.out.print("ID : " + record.getId() ); System.out.print(", Name : " + record.getName() ); System.out.print(", Marks : " + record.getMarks()); System.out.print(", Year : " + record.getYear()); System.out.println(", Age : " + record.getAge()); } } }
以下是設置裝備擺設文件beans.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- Initialization for data source --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/TEST"/> <property name="username" value="root"/> <property name="password" value="cohondob"/> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="create"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="createOperation" expression="execution(* com.yiibai.StudentJDBCTemplate.create(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/> </aop:config> <!-- Initialization for TransactionManager --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- Definition for studentJDBCTemplate bean --> <bean id="studentJDBCTemplate" class="com.yiibai.StudentJDBCTemplate"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
創立源代碼和bean設置裝備擺設文件來完成,讓我們運轉運用法式。假如一切順遂,這將打印以下,將激發異常。在這類情形下,事務將回滾,並沒有記載將在數據庫表中創立。
------Records creation-------- Created Name = Zara, Age = 11 Exception in thread "main" java.lang.RuntimeException: simulate Error condition
你可以嘗嘗下面的例子中去除異常後,在這類情形下,應當提交事務,應當看到在數據庫中的記載。