您的位置:首页 > 编程语言 > Java开发

springboot 操作数据库的封装

2017-12-23 16:45 405 查看
参考https://gitee.com/234gdfgsdf/drei-wolke-platform项目
springboot springcloud中需要经常使用到关系型数据库或者非关系型数据库,这里做了一个maven的基本模块,别人需要使用关系型或非关系数据库redis时,加入maven依赖即可,代码如下:

<!-- 关系型和非关系型数据库配置 -->
<dependency>
<groupId>com.neusoft.unieap</groupId>
<artifactId>unieap-db-core</artifactId>
<version>${unieap.platform.version}</version>
</dependency>

unieap-db-core的构思,加入druid数据源操作mysql或者oracle同时支持redis的存储。
pom文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">;
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.neusoft.unieap</groupId>
<artifactId>micro-unieap-platform</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>unieap-db-core</artifactId>

<dependencies>
<!-- 加入redis的处理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 使用jasypt对springboot的datasource密码加密 -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.8</version>
</dependency>

<!-- 增加jdbc的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

<!-- owen加入druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
<!-- owen增加oracle的支持 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>

<!-- owen增加mybatis的支持 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>

<!-- lombok setter getter 标签 -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<!-- 字符串操作的commons包 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>

</dependencies>

</project>

application.yml文件
server:
port: 7777
tomcat:
uri-encoding: UTF-8
spring:
application:
name: unieap-crontab-core
http:
encoding:
charset: utf8
force: true
enabled: true
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
username: crm_owner_user
password: bss_crm_test
filters: stat,wall
redis:
database: 1
cluster:
nodes:
130.75.131.237:7000,130.75.131.238:7000,130.75.131.239:7000,130.75.131.237:7001,130.75.131.238:7001,130.75.131.239:7001

timeout: 1000 # 连接超时时间(毫秒)
pool:
max-active: 10  # 连接池最大连接数(使用负值表示没有限制)
max-idle: 8     # 连接池中的最大空闲连接
min-idle: 2     # 连接池中的最小空闲连接
max-wait: 100   # 连接池最大阻塞等待时间(使用负值表示没有限制)

mybatis:
config-location: classpath:mybatis.cfg.xml
mapper-locations: classpath*:com/neusoft/*/dao/.xml

logging:
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
com.neusoft: DEBUG
com.netflix: DEBUG #用于心跳检测输出的日志

代码文件结构如下



redis代码说明
redis是key-value的存储,为了保证redis的性能,可以将数据分片存储,例如将oauth2的信息分片存储
"access:111111";
"auth_to_access:111111";
"auth:111111";
"refresh_auth:111111";
"access_to_refresh:111111";
"refresh:111111";
"refresh_to_access:111111";
"client_id_to_access:111111";
"uname_to_access:111111";
key都是111111,加前缀分散存储,废话不多说回到redis构建部分,java需要一个key-value序列化的工具 代码如下

package com.neusoft.unieap.redis.config.util;

/**

@author 作者 owen E-mail: 624191343@qq.com

@version 创建时间:2017年7月12日 上午10:50:19

类说明
*/
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

// 此时定义的序列化操作表示可以序列化所有类的对象,当然,这个对象所在的类一定要实现序列化接口
public class RedisObjectSerializer implements RedisSerializer<Object> {
// 为了方便进行对象与字节数组的转换,所以应该首先准备出两个转换器
private Converter<Object, byte[]> serializingConverter = new SerializingConverter();
private Converter<byte[], Object> deserializingConverter = new DeserializingConverter();
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; // 做一个空数组,不是null

@Override
public byte[] serialize(Object obj) throws SerializationException {
if (obj == null) { // 这个时候没有要序列化的对象出现,所以返回的字节数组应该就是一个空数组
return EMPTY_BYTE_ARRAY;
}
return this.serializingConverter.convert(obj); // 将对象变为字节数组
}

@Override
public Object deserialize(byte[] data) throws SerializationException {
if (data == null || data.length == 0) { // 此时没有对象的内容信息
return null;
}
return this.deserializingConverter.convert(data);
}

}

序列化工具准备好后,配置redistemplate操作类注入到spring容器中供别人操作使用
package com.neusoft.unieap.redis.config;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import com.neusoft.unieap.redis.config.util.RedisObjectSerializer;

/**

@author 作者 owen E-mail: 624191343@qq.com

@version 创建时间:2017年7月12日 下午3:28:10 类说明[url=mailto:br/>*/
@Configuration
*/
@Configuration
@ConditionalOnProperty( name="spring.redis.cluster.nodes" , matchIfMissing=false)
public class RedisConfig {

@Bean("redisTemplate")[url=mailto:br/>@Primary
@Primary
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(factory);

RedisSerializer stringSerializer = new StringRedisSerializer();
RedisSerializer redisObjectSerializer = new RedisObjectSerializer();
redisTemplate.setKeySerializer(stringSerializer); // key的序列化类型
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(redisObjectSerializer); // value的序列化类型
redisTemplate.afterPropertiesSet();

redisTemplate.opsForValue().set("hello", "wolrd");

return redisTemplate;

}

}

这时,redis的封装已经结束,我们开始下一步关系型数据库的构建,报文采取的是oracle数据库,支持单数据源以及多数据源的方式。
单数据源整合druid的代码如下
package com.neusoft.unieap.db.config;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;

/**

@author 作者 owen E-mail: 624191343@qq.com

@version 创建时间:2017年11月9日 下午1:47:37 类说明
*/

@Configuration
@ConditionalOnProperty(name = { "spring.datasource.enable.dynamic" }, matchIfMissing = true)
public class DruidConfig {

// 将druid纳入监控步骤如下
// 1通过springboot配置文件注入datasource中
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = false)
public DataSource druidDataSource() {
return DataSourceBuilder.create().type(DruidDataSource.class).build();
}

// 2.StatViewServlet注入到spring中
// Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。
// 这个StatViewServlet的用途包括:
// 提供监控信息展示的html页面
// 提供监控信息的JSON API
// 注意:使用StatViewServlet,建议使用druid 0.2.6以上版本。
// 注入第三方没有注解的servlet
@Bean
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = false)
public ServletRegistrationBean druidServlet() { // 主要实现WEB监控的配置处理
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),
"/druid/*"); // 现在要进行druid监控的配置处理操作
servletRegistrationBean.addInitParameter("allow", "127.0.0.1,130.75.131.208"); // 白名单
servletRegistrationBean.addInitParameter("deny", "192.168.28.200"); // 黑名单
servletRegistrationBean.addInitParameter("loginUsername", "owen"); // 用户名
servletRegistrationBean.addInitParameter("loginPassword", "1q2w3e4r"); // 密码
servletRegistrationBean.addInitParameter("resetEnable", "false"); // 是否可以重置数据源
return servletRegistrationBean;
}

// 3.对请求进行过滤
// WebStatFilter注入到spring容器中
// 注入第三方没有注解的过滤器
@Bean
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = false)
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*"); // 所有请求进行监控处理
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.css,/druid/*");
return filterRegistrationBean;
}

}

此时单库的数据源集成druid mybatis已经集成完毕,下面说明动态数据源的配置。
1.需要继承spring的动态数据源
package com.neusoft.unieap.db.config.dynamic.config.util;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**

@author 作者 owen E-mail: 624191343@qq.com

@version 创建时间:2017年11月10日 下午3:52:46

类说明
*/
public class DynamicDataSource extends AbstractRoutingDataSource{

private Map<Object, Object> datasources;

public DynamicDataSource() {
datasources = new HashMap<>();

super.setTargetDataSources(datasources);

}

public <T extends DataSource> void addDataSource(DataSourceKey key, T data) {
datasources.put(key, data);
}

@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSourceKey();
}

}

2.定义两个库的标识
package com.neusoft.unieap.db.config.dynamic.config.util;
/**

数据源定义

@author owen

@create 2017年7月2日
*/
public enum DataSourceKey {
crm, bill
}

3.定义线程变量,供每个调用时分配动态数据源
package com.neusoft.unieap.db.config.dynamic.config.util;

/**

用于数据源切换

@author owen

@create 2017年7月2日
*/
public class DataSourceHolder {
private static final ThreadLocal<DataSourceKey> dataSourceKey = new ThreadLocal<>();

public static DataSourceKey getDataSourceKey() {
return dataSourceKey.get();
}

public static void setDataSourceKey(DataSourceKey type) {
dataSourceKey.set(type);
}

public static void clearDataSourceKey() {
dataSourceKey.remove();
}

}
4.springboot整合动态数据源双库配置
package com.neusoft.unieap.db.config.dynamic.config;

import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.neusoft.unieap.db.config.dynamic.config.util.DataSourceKey;
import com.neusoft.unieap.db.config.dynamic.config.util.DynamicDataSource;

/**

定义数据源

@author owen

@create 2017年7月2日[url=mailto:br/>*/
@Configuration
*/
@Configuration
@ConditionalOnProperty(name = { "spring.datasource.enable.dynamic" }, matchIfMissing = false, havingValue = "true")
public class DynamicDataSourceConfig {

private Logger logger = LoggerFactory.getLogger(DynamicDataSourceConfig.class);

// crm库[url=mailto:br/>@Value(]br/>@Value("${spring.datasource.primary.url:#{null}}")
@Value("${spring.datasource.primary.username: #{null}}")
private String primaryUsername;[url=mailto:br/>@Value(]br/>@Value("${spring.datasource.primary.password:#{null}}")
@Value(]br/>@Value("${spring.datasource.secondary.url:#{null}}")
@Value("${spring.datasource.secondary.username: #{null}}")
private String secondaryUsername;[url=mailto:br/>@Value(]br/>@Value("${spring.datasource.secondary.password:#{null}}")
@Value(]br/>@Value("${spring.datasource.driverClassName:#{null}}")
@Value(]br/>@Value("${spring.datasource.initialSize:#{null}}")
@Value(]br/>@Value("${spring.datasource.minIdle:#{null}}")
@Value(]br/>@Value("${spring.datasource.maxActive:#{null}}")
@Value(]br/>@Value("${spring.datasource.maxWait:#{null}}")
@Value(]br/>@Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
@Value(]br/>@Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
@Value(]br/>@Value("${spring.datasource.validationQuery:#{null}}")
@Value(]br/>@Value("${spring.datasource.testWhileIdle:#{null}}")
@Value(]br/>@Value("${spring.datasource.testOnBorrow:#{null}}")
@Value(]br/>@Value("${spring.datasource.testOnReturn:#{null}}")
@Value(]br/>@Value("${spring.datasource.poolPreparedStatements:#{null}}")
@Value(]br/>@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
@Value(]br/>@Value("${spring.datasource.filters:#{null}}")
@Value(]br/>@Value("{spring.datasource.connectionProperties:#{null}}")
public DataSource crmDataSource() {
DruidDataSource crmDataSource = new DruidDataSource();
crmDataSource.setUrl(this.primaryDbUrl);
crmDataSource.setUsername(this.primaryUsername);// 用户名
crmDataSource.setPassword(this.primaryPassword);// 密码
crmDataSource.setDriverClassName(driverClassName);
this.setCommons(crmDataSource);
return crmDataSource;
}

// 不需要纳入spring容器
public DataSource billDataSource() {
DruidDataSource billDataSource = new DruidDataSource();
billDataSource.setUrl(secondaryDbUrl);
billDataSource.setUsername(secondaryUsername);// 用户名
billDataSource.setPassword(secondaryPassword);// 密码
billDataSource.setDriverClassName(driverClassName);

this.setCommons(billDataSource);

return billDataSource;

}

@Bean // 只需要纳入动态数据源到spring容器[url=mailto:br/>@Primary
@Primary
DynamicDataSource dataSource = new DynamicDataSource();
DataSource crmDataSource = this.crmDataSource();
DataSource billDataSource = this.billDataSource();
dataSource.addDataSource(DataSourceKey.crm, crmDataSource);
dataSource.addDataSource(DataSourceKey.bill, billDataSource);
dataSource.setDefaultTargetDataSource(crmDataSource);

return dataSource;

}

@Bean
public StatFilter statFilter() {
StatFilter statFilter = new StatFilter();
statFilter.setLogSlowSql(true);
statFilter.setMergeSql(true);
statFilter.setSlowSqlMillis(1000);

return statFilter;

}

@Bean
public WallFilter wallFilter() {
WallFilter wallFilter = new WallFilter();

// 允许执行多条SQL
WallConfig config = new WallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);

return wallFilter;

}

@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings("/druid/*");
return servletRegistrationBean;
}

@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {

return new JdbcTemplate(dataSource);

}

@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {

return new NamedParameterJdbcTemplate(dataSource);

}

private void setCommons(DruidDataSource dataSource) {
// configuration
if (initialSize != null) {
dataSource.setInitialSize(initialSize);
}
if (minIdle != null) {
dataSource.setMinIdle(minIdle);
}
if (maxActive != null) {
dataSource.setMaxActive(maxActive);
}
if (maxWait != null) {
dataSource.setMaxWait(maxWait);
}
if (timeBetweenEvictionRunsMillis != null) {
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
if (minEvictableIdleTimeMillis != null) {
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
if (validationQuery != null) {
dataSource.setValidationQuery(validationQuery);
}
if (testWhileIdle != null) {
dataSource.setTestWhileIdle(testWhileIdle);
}
if (testOnBorrow != null) {
dataSource.setTestOnBorrow(testOnBorrow);
}
if (testOnReturn != null) {
dataSource.setTestOnReturn(testOnReturn);
}
if (poolPreparedStatements != null) {
dataSource.setPoolPreparedStatements(poolPreparedStatements);
}
if (maxPoolPreparedStatementPerConnectionSize != null) {
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
}

if (connectionProperties != null) {
dataSource.setConnectionProperties(connectionProperties);
}

List<Filter> filters = new ArrayList<>();
filters.add(statFilter());
filters.add(wallFilter());
dataSource.setProxyFilters(filters);

}

@Bean // 将数据源纳入spring事物管理[url=mailto:br/>@Primary
@Primary
return new DataSourceTransactionManager(dataSource);
}

@Bean
public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

}

此处一个支持单数据源或者多数据源的关系型数据库核心模块已经集成完毕,支持redis-cluster分布式redis存储的nosql核心模块也已经集成完毕,可以根据业务看是否集成elasticsearch mogondb等存储到此模块,目前我们只使用oracle和redis,只做了以上封装。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  springboot mybatis