之前的項目一直在用Mybatis,不過因爲sql都比較複雜,所Mybatis實現起來很方便。但一些簡單的增刪改查卻也要寫sql就比較麻煩了,畢竟代碼的話能少寫一點是一點。於是開始打算用JPA來做一些簡單的小服務。
一. yml文件配置
項目就直接用STS建了,導包也直接在建項目時勾選就行。
如果只是單獨的數據源的話直接配置yml使用Spring Boot的datasource配置方式就行。(其中自帶有四種連接池)
不過我寫的demo使用的是阿里的druid,所以可根據使用的連接池更換不同的寫法。下面貼上我application.yml文件的配置。
server:
port: 8888
spring:
application:
name: lcy-many-datesource
datasource:
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# poolPreparedStatements: Oracle爲true,MySql可爲false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
testdb:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://132.97.61.65:3306/test?useUnicode=true&characterEncoding=utf-8
username: itsm
password: whtisson
demodb:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://132.97.61.65:3306/demo?useUnicode=true&characterEncoding=utf-8
username: itsm
password: whtisson
jpa:
show-sql: true
hibernate:
ddl-auto: update
這裏我把連接數配置、連接健康狀況檢查配置都寫成了公共部分,而testdb和demodb兩個數據庫配置單獨分開寫。因爲這裏懶得建表了所以直接把ddl - auto設置爲update讓它自己建表。
二. 類配置
因爲Spring Boot不使用xml文件進行配置,所以使用類來完成entity類、repository接口等相關的配置。而JPA的主要獲取:DataSource、EntityManagerFactory和PlatformTransactionManager,具體配置如下。
1. DruidDataSourceConfig.java (Druid配置)
package com.lcy.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.alibaba.druid.pool.DruidDataSource;
/**
* @ClassName: DruidDataSourceConfig
* @Description: 總數據源配置類
* @author lcy
* @date 2018年4月4日 下午2:36:26
*/
@Configuration
public class DruidDataSourceConfig {
private Logger log = LoggerFactory.getLogger(DruidDataSourceConfig.class);
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private int maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("{spring.datasource.connectionProperties}")
private String connectionProperties;
/* #####################基礎公共配置##################### */
@Value("${spring.datasource.testdb.url}")
private String testUrl;
@Value("${spring.datasource.testdb.username}")
private String testUsername;
@Value("${spring.datasource.testdb.password}")
private String testPassword;
@Value("${spring.datasource.testdb.driverClassName}")
private String testDriverClassName;
@Bean(name = "testDataSource")
@Primary // 確定主數據源
public DataSource testDataSource() {
log.info("創建testDataSource數據源");
return createDataSource(testUrl, testUsername, testPassword, testDriverClassName);
}
/* #####################testDataSource配置##################### */
@Value("${spring.datasource.demodb.url}")
private String demoUrl;
@Value("${spring.datasource.demodb.username}")
private String demoUsername;
@Value("${spring.datasource.demodb.password}")
private String demoPassword;
@Value("${spring.datasource.demodb.driverClassName}")
private String demoDriverClassName;
@Bean(name = "demoDataSource")
public DataSource demoDataSource() {
log.info("創建demoDataSource數據源");
return createDataSource(demoUrl, demoUsername, demoPassword, demoDriverClassName);
}
/* #####################demoDataSource配置##################### */
private DataSource createDataSource(String url, String username, String password, String driverClassName) {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
// configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
}
這個配置應該沒有特別要說明的,聲明一個阿里的Datasource對象,將yml中的參數set進去後控制反轉,設置一個唯一的Bean的name即可。
2. TestDataSourceConfig.java (數據源一配置)
package com.lcy.config;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @ClassName: TestDataSourceConfig
* @Description: Test數據源配置類
* @author lcy
* @date 2018年4月4日 下午3:05:44
*/
@Configuration
@EnableTransactionManagement // 開啓註解事務管理
@EnableJpaRepositories(entityManagerFactoryRef = "testEntityManagerFactory", // 實體類工廠依賴
transactionManagerRef = "testTransactionManager", // 事務依賴
basePackages = "com.lcy.repository.test") // repository類所在的包
public class TestDataSourceConfig {
private Logger log = LoggerFactory.getLogger(TestDataSourceConfig.class);
@Autowired
private JpaProperties jpaProperties;
@Autowired
@Qualifier("testDataSource")
private DataSource dataSource;
/*
* 通過LocalContainerEntityManagerFactoryBean來獲取EntityManagerFactory實例
*/
@Bean(name = "testEntityManagerFactoryBean")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
log.info("創建testEntityManagerFactoryBean");
return builder.dataSource(dataSource)// 設置使用的數據源
.properties(jpaProperties.getHibernateProperties(dataSource))// 設置JPA屬性
.packages("com.lcy.entity.test")// 設置實體類所在的包
// 持久性單元的名稱,如果只構建一個EntityManagerFactory,可以省略它,
// 但是如果在同一個應用程序中有多個,應該給它們起不同的名稱。
.persistenceUnit("testPersistenceUnit")
.build();
// 不要在這裏直接獲取EntityManagerFactory
}
/*
* EntityManagerFactory類似於Hibernate的SessionFactory,mybatis的SqlSessionFactory
* 總之,在執行操作之前,我們總要獲取一個EntityManager,這就類似於Hibernate的Session,
* mybatis的sqlSession.
*/
@Bean(name = "testEntityManagerFactory")
@Primary
public EntityManagerFactory entityManagerFactory(EntityManagerFactoryBuilder builder) {
log.info("創建testEntityManagerFactory");
return this.entityManagerFactoryBean(builder).getObject();
}
/*
* 配置事務管理器
*/
@Bean(name = "testTransactionManager")
@Primary
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
log.info("創建testTransactionManager");
return new JpaTransactionManager(this.entityManagerFactory(builder));
}
}
- @Primary註解在這裏依舊是強調主數據源而已,不加並不影響。
- 依賴注入Datasource時一定要加@Qualifier來聲明要注入的Bean是哪個,不然會默認注入DataSourceConfig.java中加了@Primary的Datasource。
3. DemoDataSourceConfig.java (數據源二配置)
package com.lcy.config;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "demoEntityManagerFactory",
transactionManagerRef = "demoTransactionManager",
basePackages = "com.lcy.repository.demo")
public class DemoDataSourceConfig {
private Logger log = LoggerFactory.getLogger(TestDataSourceConfig.class);
@Autowired
private JpaProperties jpaProperties;
@Autowired
@Qualifier("demoDataSource")
private DataSource dataSource;
@Bean(name = "demoEntityManagerFactoryBean")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder){
log.info("創建demoEntityManagerFactoryBean");
return builder
.dataSource(dataSource)
.properties(jpaProperties.getHibernateProperties(dataSource))
.packages("com.lcy.entity.demo")
.persistenceUnit("demoPersistenceUnit")
.build();
}
@Bean(name = "demoEntityManagerFactory")
public EntityManagerFactory entityManagerFactory(EntityManagerFactoryBuilder builder){
log.info("創建demoEntityManagerFactory");
return this.entityManagerFactoryBean(builder).getObject();
}
@Bean(name = "demoTransactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder){
log.info("創建demoTransactionManager");
return new JpaTransactionManager(this.entityManagerFactory(builder));
}
}
基本結構入圖,只要在配置中的包路徑配置正確就可以操作不同的數據源了。