- 单个数据源
- 引入依赖
<!--
spring-boot-starter-jdbc依赖与HikariCP和spring-jdbc
HikariCP:spring boot 2.0默认使用的数据连接池(传说最快)
spring-jdbc:针对JDBC操作spring封装的api
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--示例使用mysql 8作数据库、这里引入mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- 数据源配置
#mysql8 使用com.mysql.cj.jdbc.Driver驱动,PS:serverTimezone=GMT需要加上,不然服务器时间不能同步
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5 - 使用spring封装的api执行sql
dao接口:
public interface TestDao {
/** 新增一条数据 */
public int insert(EntityTest test)throws RuntimeException;
/** 修改一条数据 */
public int update(EntityTest test)throws RuntimeException;
/** 根据主键删除一条数据 */
public int delete(Integer id)throws RuntimeException;
/** 查询全部数据 */
public List<EntityTest> select()throws RuntimeException;
/** 根据主键查询一条数据 */
public EntityTest select(Integer id)throws RuntimeException;
}
dao实现类:
@Repository("testDao")
public class TestDaoImpl implements TestDao {
/** spring boot 自带JDBC api */
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int insert(EntityTest test) throws RuntimeException {
// TODO Auto-generated method stub
String sql ="insert into t_test (createDatetime,remark) values (?,?)";
Date createDatetime = test.getCreateDatetime();
String remark = test.getRemark();
return jdbcTemplate.update(sql, createDatetime,remark);
}
@Override
public int update(EntityTest test) throws RuntimeException {
// TODO Auto-generated method stub
String sql ="update t_test set createDatetime = ?,remark = ? where id = ?";
Date createDatetime = test.getCreateDatetime();
String remark = test.getRemark();
Integer id = test.getId();
return jdbcTemplate.update(sql, createDatetime,remark,id);
}
@Override
public int delete(Integer id) throws RuntimeException {
// TODO Auto-generated method stub
String sql = "delete from t_test where id = ?";
return jdbcTemplate.update(sql, id);
}
@Override
public List<EntityTest> select() throws RuntimeException {
// TODO Auto-generated method stub
String sql = "select id,createDatetime,remark from t_test order by createDatetime desc";
// 这种方式通过自己映射的字段与数学集合来反馈
return jdbcTemplate.query(sql, new entityTestResult());
// 这种方式通过框架自动映射来反馈
// return jdbcTemplate.query(sql, new BeanPropertyRowMapper<EntityTest>(EntityTest.class));
}
@Override
public EntityTest select(Integer id) throws RuntimeException {
// TODO Auto-generated method stub
String sql = "select id,createDatetime,remark from t_test where id=?";
return jdbcTemplate.queryForObject(sql, new Object[] {id}, new BeanPropertyRowMapper<EntityTest>(EntityTest.class));
}
/**
* 字段与属性封装
* @author kyoxue
* @date 2019年10月28日
*/
class entityTestResult implements RowMapper<EntityTest>{
@Override
public EntityTest mapRow(ResultSet rs, int rowNum) throws SQLException {
// TODO Auto-generated method stub
EntityTest test = new EntityTest();
test.setId(rs.getInt("id"));
test.setCreateDatetime(rs.getDate("createDatetime"));
test.setRemark(rs.getString("remark"));
return test;
}
}
}
封装用的实体:
public class EntityTest {
private Integer id;
private Date createDatetime;
private String remark;
//gettter...setter...
@Override
public String toString() {
// TODO Auto-generated method stub
StringBuffer buff = new StringBuffer();
buff.append("id:").append(this.id).append(" ");
buff.append("createDatetime:").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.getCreateDatetime())).append(" ");
buff.append("remark:").append(this.remark).append(" ");
return buff.toString();
}
}
- 附上示例库表以及test
USE `test`;
DROP TABLE IF EXISTS `t_test`;
-- 注意DEFAULT CHARSET utf8 COLLATE utf8_general_ci 是之前老版sql的写法。
-- mysql8使用DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci
CREATE TABLE `t_test` (
`id` INT AUTO_INCREMENT NOT NULL PRIMARY KEY COMMENT 'primary key',
`createDatetime` DATETIME NULL COMMENT 'create time',
`remark` VARCHAR(500) NULL COMMENT 'remark',
KEY(createDatetime)
) ENGINE=INNODB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT='test table';
使用junit测试:
/**
* 集成springboot环境测试,主要测后台服务,dao等需要@autoware注入依赖的功能
* 这里因为项目加入了websocket例子,所以将test引入容器环境并随机开端口,
* 否则会报javax.websocket.server.ServerContainer not available
* 如果没有websocket,(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)可以去除
* @author kyoxue
* @date 2019年10月15日
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class applicationTest {
@Autowired
private TestDao testDao;
@Test
public void testJDBC()throws Exception{
/** add */
// EntityTest test = new EntityTest();
// test.setCreateDatetime(new Date());
// test.setRemark("test remark");
// testDao.insert(test);
/** find by primary key */
// EntityTest test = testDao.select(1);
// assertNotEquals(test, null);
// System.out.println(test.toString());
/** update */
// test.setRemark("new remark");
// testDao.update(test);
/** find table data all */
// List<EntityTest> tests = testDao.select();
// assertNotEquals(tests, null);
// for (EntityTest entityTest : tests) {
// System.out.println(entityTest.toString());
// }
/** delete data by primary key*/
// testDao.delete(1);
}
}
- 多数据源
- 依赖和单数据源一致,见上面
- 数据源配置(原先单数据源配置和单数据源的程序示例全部删掉,否则引起冲突不兼容)
一个项目最好要么多数据源配置,要么就单数据源。
这里把上面单数据源配置也换成了多数据源配置方式。
spring.datasource.test.driver-class-name=com.mysql.cj.jdbc.Driver
#新版本mysql,必须带上时区说明serverTimezone=GMT
#GMT会少了8小时,所以这里用GMT+8,转义后:GMT%2b8
spring.datasource.test.jdbc-url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2b8&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=true
spring.datasource.test.username=root
spring.datasource.test.password=
spring.datasource.test.max-idle=10
spring.datasource.test.max-wait=10000
spring.datasource.test.min-idle=5
spring.datasource.test.initial-size=5
本地 订单数据源配置
spring.datasource.order.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.order.jdbc-url=jdbc:mysql://localhost:3306/order?serverTimezone=GMT%2b8&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=true
spring.datasource.order.username=root
spring.datasource.order.password=
spring.datasource.order.max-idle=10
spring.datasource.order.max-wait=10000
spring.datasource.order.min-idle=5
spring.datasource.order.initial-size=5
1.251 业务数据源配置
spring.datasource.report.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.report.jdbc-url=jdbc:mysql://xxx.xxx.xxx.xxx:3306/xx?serverTimezone=GMT%2b8&autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=true
spring.datasource.report.username=root
spring.datasource.report.password=
spring.datasource.report.max-idle=10
spring.datasource.report.max-wait=10000
spring.datasource.report.min-idle=5
spring.datasource.report.initial-size=5
这里配置有个共同点,分别有相同的前缀:spring.datasource.test、spring.datasource.order、spring.datasource.report,以此区分数据源配置
注意:多数据源用的是HikariCP连接池,驱动key用driver-class-name,连接地址key用jdbc-url
因为多数据源,所以要定义不同的DataSource对像从而获取不同的JdbcTemplate对象。
新建个springboot Configuration(在SpringBootApplication即启动入口类同目录下)
主要针对不同数据源生成不同的DataSource,同时设置配置文件数据源对应前缀和返回DataSource对象的别名。
@Qualifier:当存在相同bean配置多个的时候,这时候需要取别名区分
@Primary: 如果系统认识不了用哪个的时候,会优先选择该注解对应的bean
@ConfigurationProperties:给对应的DataSource通过配置前缀找到参数信息
/**
* jdbc多数据集源配置
* @author kyoxue
* @date 2019年10月28日
*/
@Configuration
public class DemoDBConfiguration {
/** 定义数据源 */
//默认数据源
@Primary
//bean名称
@Bean(name="orderDB")
//为数据源取别名区分
@Qualifier("orderDB")
//指定配置数据源前缀
@ConfigurationProperties("spring.datasource.order")
public DataSource orderDB() {
return DataSourceBuilder.create().build();
}
//bean名称
@Bean(name="reportDB")
//为数据源取别名区分
@Qualifier("reportDB")
//指定配置数据源前缀
@ConfigurationProperties("spring.datasource.report")
public DataSource reportDB() {
return DataSourceBuilder.create().build();
}
//bean名称
@Bean(name="testDB")
//为数据源取别名区分
@Qualifier("testDB")
//指定配置数据源前缀
@ConfigurationProperties("spring.datasource.test")
public DataSource testDB() {
return DataSourceBuilder.create().build();
}
/** 定义API */
//生成api对象 -- 订单操作
@Bean(name = "orderApi")
public JdbcTemplate orderApi(@Qualifier("orderDB") DataSource db) {
return new JdbcTemplate(db);
}
//生成api对象 -- 业务操作
@Bean(name = "reportApi")
public JdbcTemplate reportApi(@Qualifier("reportDB") DataSource db) {
return new JdbcTemplate(db);
}
//生成api对象 -- test
@Bean(name = "testApi")
public JdbcTemplate testApi(@Qualifier("testDB") DataSource db) {
return new JdbcTemplate(db);
}
}
- 使用多数据源配置生成的对应api进行不同数据源的sql操作
新建各个数据源对应的实体对象(test的实体上面已经列出)
/** reportDB下的一张配置表*/
public class EntityConfig {
private String code;
private String value;
private String remark;
private String creater;
private String modifier;
private Date createTime;
private Date modifyTime;
private String state;
//setter...getter...
@Override
public String toString() {
// TODO Auto-generated method stub
StringBuffer buffer = new StringBuffer();
buffer.append("code:").append(code).append(" ");
buffer.append("value:").append(value).append(" ");
buffer.append("remark:").append(remark).append(" ");
buffer.append("creater:").append(creater).append(" ");
buffer.append("createTime:").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(createTime)).append(" ");
buffer.append("state:").append(state).append(" ");
return buffer.toString();
}
}
/** orderDB下的一张示例订单表*/
public class EntityOrder {
private Long id;
private Date createDatetime;
private String orderNo;
//setter...getter...
}
为了简单,这里新建一个公共的dao接口:
public interface CommDao<T> {
/** 新增一条数据 */
public int insert(T t)throws RuntimeException;
/** 修改一条数据 */
public int update(T t)throws RuntimeException;
/** 根据主键删除一条数据 */
public int delete(Object id)throws RuntimeException;
/** 查询全部数据 */
public List<T> select()throws RuntimeException;
/** 根据主键查询一条数据 */
public T select(Object id)throws RuntimeException;
}
然后order和report分别新建dao实现类(这里只为了演示多数据源操作,所以方法没全部实现)
@Repository("testOrderDao")
public class TestOrderDaoImpl implements CommDao<EntityOrder> {
@Autowired
private JdbcTemplate orderApi;
@Override
public int insert(EntityOrder t) throws RuntimeException {
// TODO Auto-generated method stub
String sql = "insert into t_order(createDatetime,orderNo) values(?,?)";
return orderApi.update(sql, t.getCreateDatetime(),t.getOrderNo());
}
@Override
public int update(EntityOrder t) throws RuntimeException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int delete(Object id) throws RuntimeException {
// TODO Auto-generated method stub
return 0;
}
@Override
public List<EntityOrder> select() throws RuntimeException {
// TODO Auto-generated method stub
return null;
}
@Override
public EntityOrder select(Object id) throws RuntimeException {
// TODO Auto-generated method stub
return null;
}
}
@Repository("testReportDao")
public class TestReportDaoImpl implements CommDao<EntityConfig> {
@Autowired
private JdbcTemplate reportApi;
@Override
public int insert(EntityConfig t) throws RuntimeException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int update(EntityConfig t) throws RuntimeException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int delete(Object id) throws RuntimeException {
// TODO Auto-generated method stub
return 0;
}
@Override
public List<EntityConfig> select() throws RuntimeException {
// TODO Auto-generated method stub
return null;
}
@Override
public EntityConfig select(Object id) throws RuntimeException {
// TODO Auto-generated method stub
String sql = "select * from t_gnzl_config where code = ?";
return reportApi.queryForObject(sql, new Object[] {id}, new BeanPropertyRowMapper<EntityConfig>(EntityConfig.class));
}
}
- 附上额外示例的表
-- 这是一张本机另外库order里的一张t_order表
DROP TABLE IF EXISTS `t_order`;
-- 注意DEFAULT CHARSET utf8 COLLATE utf8_general_ci 是之前老版sql的写法。
-- mysql8使用DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci
CREATE TABLE `t_order` (
`id` BIGINT auto_increment not null primary key comment 'primary key',
`createDatetime` datetime null comment 'create time',
`orderNo` varchar(25) not null comment 'order no',
key(`orderNo`)
) ENGINE=innodb DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT='order table';
-- 这是一张不在本机的xxx库中的t_gnzl_config表
USE `xxx`;
DROP TABLE IF EXISTS `t_gnzl_config`;
CREATE TABLE `t_gnzl_config` (
`code` char(6) NOT NULL COMMENT '配置KEY',
`value` varchar(1024) DEFAULT NULL COMMENT '配置信息',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`creater` varchar(64) NOT NULL,
`createTime` datetime NOT NULL,
`modifier` varchar(64) DEFAULT NULL,
`modifyTime` datetime DEFAULT NULL,
`state` char(1) NOT NULL DEFAULT 'Y',
PRIMARY KEY (`code`),
UNIQUE KEY `_u_code` (`code`)
) ENGINE=innodb DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT='xxx配置信息表';
- 使用junit测试(这里只执行了下reportDB对应的数据源,测试成功!~)
/**
* 集成springboot环境测试,主要测后台服务,dao等需要@autoware注入依赖的功能
* 这里因为项目加入了websocket例子,所以将test引入容器环境并随机开端口,
* 否则会报javax.websocket.server.ServerContainer not available
* 如果没有websocket,(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)可以去除
* @author kyoxue
* @date 2019年10月15日
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class applicationTest {
@Autowired
private CommDao<EntityConfig> testReportDao;
@Test
public void testJDBC2()throws Exception{
EntityConfig entityConfig = testReportDao.select("xxxx");
assertNotEquals(entityConfig, null);
System.out.println(entityConfig.toString());
}
}
-
springboot jdbc over...
ps:数据源配置很多时候涉及生产环境与测试环境的区分,springboot提供了默认选择环境配置文件的机制
生成2份配置,前缀都是application-,而后缀就是当前项目欲使用的配置名称,然后将后缀名称告诉springboot,就会自动激活。
在application.properties主配置中,指定环境名称:offline即使用application-offline配置文件
#单个application配置文件无法满足不同环境的配置,这里使用该配置指定配置名来区分使用
#通过application-前缀识别springboot配置文件,通过后缀指定要使用的配置文件
spring.profiles.active=offline