测试类中其实 可以使用很多注解,很方便的实现你想要的功能:
1) 事务管理: 测试完毕后自动回滚
2) 加载配置文件
3) 使用spring的注入特性:@Autowired 等的使用
4) AOP 功能:在 test方法的前后吗,执行代码进行 初始化或销毁资源等操作
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
/**
* @author stormfeng
* @date 2020-11-23 15:51
*/
@RunWith(SpringJUnit4ClassRunner.class) // 支持使用spring的个性化注解,比如 @Autowired
@ContextConfiguration(classes = {DatasourceConfig.class, DaoImpl.class}) // 加载所需的 bean 到整个 test环境中
@TestPropertySource(value = "classpath:jdbc.properties") // 获取test目录下的 classpath 文件配置
@Rollback(true) // 默认为true,自动回滚 @Transactional注解的方法,最终 数据库将不会 被改变
// @TransactionConfiguration(defaultRollback = false) //已过期,请用 @Rollback 或者 @Commit
public class DaoConfigTest {
// CREATE TABLE T_TEST (ID INT,NAME VARCHAR(50))
String TABLE = "T_TEST";
@Autowired
Dao dao;
@Transactional(value = "yourManagerName", rollbackFor = Exception.class)
@Before
public void testBefore() {
List<Map<String, Object>> maps = dao.queryList("SELECT * from " + TABLE);
System.out.println("before: " + maps);
}
/**
* 测试是否会 INSERT 成功,分别注解 @Rollback(true) 和 @Rollback(false) 试一下
*/
@Transactional(value = "yourManagerName", rollbackFor = Exception.class)
@Test
public void test01() {
int i = dao.update("TRUNCATE TABLE " + TABLE1);
System.out.println(i);
i = dao.update("INSERT INTO " + TABLE + " VALUES(1,'1') ");
System.out.println(i);
}
/**
* 测试异常时的事务管理: 配置 @Rollback(false) ,测试一下事务是否在异常后回滚
*/
@Transactional(value = "yourManagerName", rollbackFor = Exception.class)
@Test
public void test02() {
int i = dao.update("INSERT INTO " + TABLE + " VALUES(222,'2222') ");
int a = 1/0 ;
System.out.println(i);
}
@After
@Test
public void testAfter() {
List<Map<String, Object>> maps = dao.queryList("SELECT * FROM " + TABLE);
System.out.println("after:" + maps);
}
}
上文所需的DatasourceConfig.class,初始化数据源,源码参考如下:
/**
* 初始化数据源,jdbctemplate对象,事务对象
* @author stormfeng
* @date 2020-09-16 17:24
*/
@EnableTransactionManagement
@Configuration
public class DatasourceConfig {
@Bean
public DataSource dataSource(@Value("${oracle.jdbc.driverClass}") final String driverClassName,
@Value("${oracle.jdbc.dataSourceClass}") final String dataSourceClass,
@Value("${oracle.jdbc.url}") final String jdbcUrl,
@Value("${audit.jdbc.username}") final String username,
@Value("${audit.jdbc.password}") final String password,
@Value("${hikaricp.minimumIdle}") final Integer minimumIdle,
@Value("${hikaricp.maximumPoolSize}") final Integer maximumPoolSize,
@Value("${hikaricp.connectionTimeout}") final Long connectionTimeout,
@Value("${hikaricp.maxLifetime}") final Long maxLifetime,
@Value("${hikaricp.idleTimeout}") final Long idleTimeout,
@Value("${hikaricp.readOnly}") final Boolean reauditOnly,
@Value("${hikaricp.connectionInitSql}") final String connectionInitSql
) {
HikariDataSource hikariDataSource = new HikariDataSource(new HikariConfig() {{
setDataSourceClassName(dataSourceClass);
setJdbcUrl(jdbcUrl);
addDataSourceProperty("url", jdbcUrl);
setUsername(username);
setPassword(password);
setRegisterMbeans(true);
setConnectionTimeout(connectionTimeout);
setMinimumIdle(minimumIdle);
setMaximumPoolSize(maximumPoolSize);
setIdleTimeout(idleTimeout);
setMaxLifetime(maxLifetime);
setConnectionInitSql(connectionInitSql);
setReadOnly(reauditOnly);
}});
return hikariDataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource, @Value("${hikaricp.fetchSize}") Integer fetchSize) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource, true);
jdbcTemplate.setLazyInit(true);
// 必须设置 autoCommit = false,否则 该设置不起作用
jdbcTemplate.setFetchSize(fetchSize);
// jdbcTemplate.setMaxRows(50000); // 最多返回的结果行数 ,太大会导致 OOM
// jdbcTemplate.setQueryTimeout(120); // 查询数据库的最大时间
/**
* 仅对 call 存过的返回值起作用 ,Map 的大小写不区分
*/
jdbcTemplate.setResultsMapCaseInsensitive(true);
jdbcTemplate.afterPropertiesSet();
return jdbcTemplate;
}
@Bean
public PlatformTransactionManager yourManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
DaoImpl.class 就是对 jdbcTemplate的简单封装,太简单不需展示
classpath:jdbc.properties 是一些常用的 数据库配置,参考如下 :
oracle.jdbc.driverClass=oracle.jdbc.OracleDriver # 单个数据源
oracle.jdbc.dataSourceClass=oracle.jdbc.pool.OracleDataSource // 数据库连接池配置需要
#=================================================================
oracle.jdbc.url=jdbc:oracle:thin:@IP:PORT:servicename
oracle.jdbc.username=
oracle.jdbc.password=
# HikariCP config
# 是否自动提交事务,默认true
hikaricp.autoCommit=true
# 从连接池中获取可用连接的最长等待时间 2 min,超时会抛异常 SQLException 。最小 250 ms,Default: 30000 (30 seconds)
hikaricp.connectionTimeout=120000
# 允许连接处于空闲的最长时间,超时会被断开(一般是 该参数 +15s后断开,最长 +30s)。但是当池中连接数小于 minimumIdle 时,此参数不生效。 0 代表用不断开,最小 10000ms (10 seconds). Default: 600000 (10 minutes)
hikaricp.idleTimeout=300000
# 池中连接的最大生存期。正在使用中的连接永远也不会断开。强烈建议设置改参数,而且最好比数据库本身的时长限制短上几秒钟。0 表示无限生存期,当然,这取决于idleTimeout设置。默认值:1800000(30分钟)
hikaricp.maxLifetime=1800000
# 仅针对 缺少API Connection.isValid() 的老旧驱动 ,如果您的驱动程序支持JDBC4,我们强烈建议不要设置此属性。作用是 在连接池返回连接之前先测试连接是否可用。hikari 会自动检测是否兼容 JDBC4的API,并会有明确的日志报错。
#hikaricp.connectionTestQuery=SELECT * FROM DUAL
# 允许 处于空闲状态的连接的最大个数,hikari会自动补充货源,保证这个数字。为了保证最佳响应和峰值性能,最好不要设置该参数,默认 与 maximumPoolSize 一样
#hikaricp.minimumIdle=10
# 最大连接数,包括空闲和使用中的。当使用中的连接数达到该值后,再次调用 getConnection() 会被阻塞,最长等待 connectionTimeout 后超时。 默认是10
# 最佳连接数的计算公式 connections = ((cpu_core * 2) + effective_spindle_count) ,如果是SSD,effective_spindle_count = 0,参考 https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
hikaricp.minimumIdle=5
hikaricp.maximumPoolSize=15
hikaricp.readOnly=false
# 放入连接池之前,先检测该sql是否正常,如果此SQL无效或抛出异常,则 会触发标准的重试逻辑
hikaricp.connectionInitSql=SELECT 1 FROM DUAL
# 单次TCP 连接返回的结果数
hikaricp.fetchSize=200