<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                在Spring Boot中,當我們使用了`spring-boot-starter-jdbc`或`spring-boot-starter-data-jpa`依賴的時候,框 架會自動默認分別注入`DataSourceTransactionManager`或`JpaTransactionManager`。所以我們不需要任何額外 配置就可以用`@Transactional`注解進行事務的使用。 在該樣例工程中,我們引入了spring-data-jpa,并創建了`User`實體以及對User的數據訪 問對象`UserRepository`,在`ApplicationTest`類中實現了使用`UserRepository`進行數據讀寫的單元測試用例. 通過定義User的name屬性長度為5,這樣通過創建時User實體的name屬性超長就可以觸發異常產生。 ~~~ @Entity public class User { @Id @GeneratedValue private Long id; @Column(nullable = false, length = 5) private String name; @Column(nullable = false) private Integer age; // 省略構造函數、getter和setter } ~~~ 測試用例 ~~~ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(Application.class) public class ApplicationTests { @Autowired private UserRepository userRepository; @Test public void test() throws Exception { // 創建10條記錄 userRepository.save(new User("AAA", 10)); userRepository.save(new User("BBB", 20)); userRepository.save(new User("CCC", 30)); userRepository.save(new User("DDD", 40)); userRepository.save(new User("EEE", 50)); userRepository.save(new User("FFF", 60)); userRepository.save(new User("GGG", 70)); userRepository.save(new User("HHHHHHHHHH", 80)); userRepository.save(new User("III", 90)); userRepository.save(new User("JJJ", 100)); // 省略后續的一些驗證操作 } } ~~~ 執行測試用例 ~~~ 2016-05-27 10:30:35.948 WARN 2660 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1406, SQLState: 22001 2016-05-27 10:30:35.948 ERROR 2660 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Data truncation: Data too long for column 'name' at row 1 2016-05-27 10:30:35.951 WARN 2660 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Warning Code: 1406, SQLState: HY000 2016-05-27 10:30:35.951 WARN 2660 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Data too long for column 'name' at row 1 org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.DataException: could not execute statement ~~~ 此時查數據庫中,創建了name從AAA到GGG的記錄,沒有HHHHHHHHHH、III、JJJ的記錄。而若這是一個希望保證完整性操作的情況 下,AAA到GGG的記錄希望能在發生異常的時候被回退,這時候就可以使用事務讓它實現回退,做法非常簡單,我們只需要在test函數上添加 `@Transactional` 注解即可。 ~~~ @Test @Transactional public void test() throws Exception { // 省略測試內容 } ~~~ 這里主要通過單元測試演示了如何使用 @Transactional 注解來聲明一個函數需要被事務管理,通常我們單元測試為了保證每個測試之間的數據獨立,會使用 `@Rollback` 注解讓每個單元測試都能在結束時回滾。而真正在開發業務邏輯時,我們通常在service層接口中使用 `@Transactional` 來對各個業務邏輯進行事務管理的配置,例如: ~~~ public interface UserService { @Transactional User login(String name, String password); } ~~~ spring Boot 使用事務非常簡單,首先使用注解 `@EnableTransactionManagement` 開啟事務支持后,然后在訪問數據庫的Service方法上添加注解 `@Transactional `便可。 關于事務管理器,不管是JPA還是JDBC等都實現自接口 `PlatformTransactionManager` 如果你添加的是 spring-boot-starter-jdbc 依賴,框架會默認注入 `DataSourceTransactionManager` 實例。如果你添加的是 spring-boot-starter-data-jpa 依賴,框架會默認注入 `JpaTransactionManager` 實例。 你可以在啟動類中添加如下方法,Debug測試,就能知道自動注入的是 `PlatformTransactionManager` 接口的哪個實現類。 ~~~ @EnableTransactionManagement // 啟注解事務管理,等同于xml配置方式的 <tx:annotation-driven /> @SpringBootApplication public class ProfiledemoApplication { @Bean public Object testBean(PlatformTransactionManager platformTransactionManager){ System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName()); return new Object(); } public static void main(String[] args) { SpringApplication.run(ProfiledemoApplication.class, args); } } ~~~ 這些SpringBoot為我們自動做了,這些對我們并不透明,如果你項目做的比較大,添加的持久化依賴比較多,我們還是會選擇人為的指定使用哪個事務管理器。 代碼如下: ~~~ @EnableTransactionManagement @SpringBootApplication public class ProfiledemoApplication { // 其中 dataSource 框架會自動為我們注入 @Bean public PlatformTransactionManager txManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean public Object testBean(PlatformTransactionManager platformTransactionManager) { System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName()); return new Object(); } public static void main(String[] args) { SpringApplication.run(ProfiledemoApplication.class, args); } } ~~~ 在Spring容器中,我們手工注解@Bean 將被優先加載,框架不會重新實例化其他的 PlatformTransactionManager 實現類。 然后在Service中,被 @Transactional 注解的方法,將支持事務。如果注解在類上,則整個類的所有方法都默認支持事務。 對于同一個工程中存在多個事務管理器要怎么處理,請看下面的實例,具體說明請看代碼中的注釋。 @EnableTransactionManagement // 開啟注解事務管理,等同于xml配置文件中的 <tx:annotation-driven /> @SpringBootApplication public class ProfiledemoApplication implements TransactionManagementConfigurer { ~~~ @Resource(name="txManager2") private PlatformTransactionManager txManager2; // 創建事務管理器1 @Bean(name = "txManager1") public PlatformTransactionManager txManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } // 創建事務管理器2 @Bean(name = "txManager2") public PlatformTransactionManager txManager2(EntityManagerFactory factory) { return new JpaTransactionManager(factory); } // 實現接口 TransactionManagementConfigurer 方法,其返回值代表在擁有多個事務管理器的情況下默認使用的事務管理器 @Override public PlatformTransactionManager annotationDrivenTransactionManager() { return txManager2; } public static void main(String[] args) { SpringApplication.run(ProfiledemoApplication.class, args); } } ~~~ ~~~ @Component public class DevSendMessage implements SendMessage { // 使用value具體指定使用哪個事務管理器 @Transactional(value="txManager1") @Override public void send() { System.out.println(">>>>>>>>Dev Send()<<<<<<<<"); send2(); } // 在存在多個事務管理器的情況下,如果不使用value具體指定 // 則默認使用方法 annotationDrivenTransactionManager() 返回的事務管理器 @Transactional public void send2() { System.out.println(">>>>>>>>Dev Send2()<<<<<<<<"); } } ~~~ >注: 如果Spring容器中存在多個 PlatformTransactionManager 實例,并且沒有實現接口 TransactionManagementConfigurer 指定默認值,在我們在方法上使用注解 @Transactional 的時候,就必須要用value指定,如果不指定,則會拋出異常。 >對于系統需要提供默認事務管理的情況下,實現接口 TransactionManagementConfigurer 指定。 >對有的系統,為了避免不必要的問題,在業務中必須要明確指定 @Transactional 的 value 值的情況下。不建議實現接口 TransactionManagementConfigurer,這樣控制臺會明確拋出異常,開發人員就不會忘記主動指定。 > 除了指定不同的事務管理器之后,還能對事務進行隔離級別和傳播行為的控制,下面分別詳細解釋: ## 隔離級別 隔離級別是指若干個并發的事務之間的隔離程度,與我們開發時候主要相關的場景包括:臟讀取、重復讀、幻讀。 我們可以看 org.springframework.transaction.annotation.Isolation 枚舉類中定義了五個表示隔離級別的值: ~~~ public enum Isolation { DEFAULT(-1), READ_UNCOMMITTED(1), READ_COMMITTED(2), REPEATABLE_READ(4), SERIALIZABLE(8); } ~~~ * DEFAULT :這是默認值,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言,通常這值就是: READ_COMMITTED 。 * READ_UNCOMMITTED :該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止臟讀和不可重復讀,因此很少使用該隔離級別。 * READ_COMMITTED :該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀,這也是大多數情況下的推薦值。 * REPEATABLE_READ :該隔離級別表示一個事務在整個過程中可以多次重復執行某個查詢,并且每次返回的記錄都相同。即使在多次查詢之間有新增的數據滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止臟讀和不可重復讀。 * SERIALIZABLE :所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。 指定方法:通過使用 isolation 屬性設置,例如: `@Transactional(isolation = Isolation.DEFAULT)` ## 傳播行為 所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。 我們可以看 org.springframework.transaction.annotation.Propagation 枚舉類中定義了6個表示傳播行為的枚舉值: ~~~ public enum Propagation { REQUIRED(0), SUPPORTS(1), MANDATORY(2), REQUIRES_NEW(3), NOT_SUPPORTED(4), NEVER(5), NESTED(6); } ~~~ * REQUIRED :如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。 * SUPPORTS :如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。 * MANDATORY :如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。 * REQUIRES_NEW :創建一個新的事務,如果當前存在事務,則把當前事務掛起。 * NOT_SUPPORTED :以非事務方式運行,如果當前存在事務,則把當前事務掛起。 * NEVER :以非事務方式運行,如果當前存在事務,則拋出異常。 * NESTED :如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價于 REQUIRED 指定方法:通過使用 propagation 屬性設置,例如: `@Transactional(propagation = Propagation.REQUIRED)`
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看