2020 年 3 月 25 日

IT Skills 波林

Polin WEI – 資訊工作者的技術手札

Spring Boot 配置 Maria Database 與交易控制 ( Transaction )

3 min read
中興文化創意園區

中興文化創意園區

Spring Boot 配置 Maria Database 並用 EntityManager 及 TransactionManager 來作交易測試

 

在官方網站上有一篇 Accessing data with MySQL 文章中提到,若要連接 MySQL 只要application.properties中加入下列的參數,這很方便就可以配置好連接單一的資料庫。

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword

 

但若系統有需要連接到多個資料庫時,這樣的配置就不敷使用了,所以 Spring boot 有提供接口可以自行配置,首先一樣在 application.properties 加入下列參數:

# =================================
# Multi Database
# =================================
# MariaDB
db-apps.datasource.jdbcurl=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
db-apps.datasource.username=springuser
db-apps.datasource.password=ThePassword
db-apps.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

這裡要注意的是最前面都加了 db-apps 的前綴碼 ( Prefix ),要給接下來的 DbMariaConfig.java 使用。

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "emfApps",
        basePackages = {"com.apps.repository","com.apps.service"}
)
public class DbMariaConfig {
 private final Logger logger = LoggerFactory.getLogger(this.getClass());

 @Bean(name = "dsApps")
    @ConfigurationProperties(prefix = "db-apps.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = "emfApps")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setJpaProperties(hibernateProperties());

        factoryBean.setPackagesToScan("com.apps.model");
        factoryBean.setPersistenceUnitName("puApps");

        return factoryBean;
    }
 
    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager( @Qualifier("emfApps") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
    
    private Properties hibernateProperties() {
        final Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        //hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
        return hibernateProperties;
    }
}

有兩件事要注意,第一: @Bean (name=”transactionManager“) 要設成這樣,才不會出錯。第二:因為是要自行控制 Transaction 所以 hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update"); 就不要設定成自動更新,這個設定與 application.propertiesspring.jpa.hibernate.ddl-auto=update 是相同的。

 

  • 建立一個 table : authority 來作測試
DROP TABLE IF EXISTS `authority`;
CREATE TABLE authority (
 id bigint NOT NULL AUTO_INCREMENT,
 name VARCHAR(50) NOT NULL,
 description VARCHAR(100) NOT NULL,
 create_date datetime DEFAULT CURRENT_TIMESTAMP,
 update_date datetime,
 create_user bigint,
 update_user bigint,    
 CONSTRAINT authority_pkey PRIMARY KEY (id),
 CONSTRAINT uk_authority_name UNIQUE KEY(name)
);
INSERT INTO authority (id, name, description) VALUES (1, 'ADMINS', '管理者');
INSERT INTO authority (ID, NAME, description) VALUES (2, 'USERS', '一般用戶');

 

@Entity
@Data
public class Authority {

 @Id
 @GeneratedValue(strategy = IDENTITY)
 private Long id;
 
 private String name;
 private String description;
 
}

 

  • 建立 Repository : AuthorityRepository.java ,在 Spring boot 有 CrudRepository 可以不用寫任何 CRUD 的程式,就可以對 Table 裡的資料作新增、修改、刪作的作業,很方便且程式也更為簡潔優雅。
public interface AuthorityRepository extends CrudRepository<Authority, Long> {

}

 

  • Spring boot 用 Entity Manager 作交易測試,在程式第 5,6 行是從 DbMariaConfig.java 中來取得 @Bean(name = “emfApps”) ,並利用它來產生 EntityManager em,這樣就可以自行控制 Transaction。
@SpringBootTest
public class BasicTests {
 private final Logger logger = LoggerFactory.getLogger(this.getClass());

 @Autowired
 @Qualifier("emfApps") EntityManagerFactory emfApps;
 
 @Test
 void contextLoads() {
 }
 
 @Test
 void jpaEM() {     
  EntityManager em = emfApps.createEntityManager();
  try {
   em.getTransaction().begin();
   Authority authority = new Authority();
   authority.setName("Tests");
   authority.setDescription("Test group");
   em.persist(authority);
   em.getTransaction().commit();
  } catch (Exception e) {           
   logger.info(e.getMessage());
  } finally {
   if (em.getTransaction().isActive())
            em.getTransaction().rollback();
   em.close();
  }
 }
 
}

 

  • 使用 Transaction Manager 作交易測試
@SpringBootTest
public class BasicTests {
 private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
 @Autowired
 @Qualifier("transactionManager") PlatformTransactionManager txmApps;
 
 @Test
 void defTransaction() {
  DefaultTransactionDefinition def = new DefaultTransactionDefinition();
  // explicitly setting the transaction name is something that can only be done programmatically
  def.setName("txmAuthority");
  def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

  TransactionStatus status = txmApps.getTransaction(def);
  try {
   Authority authority = new Authority();
   authority.setName("Tests");
   authority.setDescription("Test group");
   authorityRepo.save(authority);
   txmApps.commit(status);  
  }
  catch (Exception e) {
   txmApps.rollback(status);
   logger.info(e.getMessage());
  }
  
 }
 
}

 

  • 由 Spring boot 的 repository 自行控制
@SpringBootTest
public class BasicTests {
 private final Logger logger = LoggerFactory.getLogger(this.getClass());

 @Autowired
 UserRepository userRepo;
 @Autowired
 AuthorityRepository authorityRepo; 

 @Test
 void jpaTransaction() {
  
  try {
   Authority authority = new Authority();           
   authority.setName("Tests");
   authority.setDescription("Test group");
   authorityRepo.save(authority);           
  } catch (Exception e) {
   logger.info(e.getMessage());         
  } 
 }
 
}

 

以上就是大致用來控制交易的不同作法

 

Copyright © All rights reserved. | Newsphere by AF themes.