一、项目目标
假设上一个项目需要部署上线,你会存在很多现实的问题需要解决,比如:提高系统性能使用数据库连接池、监视数据库执行效率及sql语句执行效率还有一般的系统接口都只接受JSON或XML的输出,如果直接输出字符串对方接口还需要写代码适配,这些都是问题,所以本次的项目目标是通过整合阿里开源项目Druid实现Java下的数据库连接池,兼任各种数据库,效率高出错小,使用量大,并且Druid还提供强大的监控和扩展功能,整合阿里开源项目FASTJSON,实现系统直接输出实体类转JSON,极大的精简了系统的转换负担,快速实现业务功能。
二、Druid介绍
先上一个Druid自己测试的各种主要数据库连接池的功能对比表格
Druid | BoneCP | DBCP | C3PO | Proxool | JBoss | Tomcat- jdbc |
|
---|---|---|---|---|---|---|---|
LRU | 是 | 否 | 是 | 否 | 是 | 是 | ? |
PSCache | 是 | 是 | 是 | 是 | 否 | 否 | 是 |
PSCache-Oracle-Optimized | 是 | 否 | 否 | 否 | 否 | 否 | 否 |
ExceptionSorter | 是 | 否 | 否 | 否 | 否 | 是 | 否 |
更新维护 | 是 | 否 | 否 | 否 | 否 | ? | 是 |
LRU是一个性能关键指标,特别Oracle,每个Connection对应数据库端的一个进程,如果数据库连接池遵从LRU,有助于数据库服务器优化,这是重要的指标。MySQL的InnoDB引擎设置有索引及数据缓存池,其中用到的LRU算法来维持缓存的命中率。
ExceptionSorter是一个很重要的容错特性,如果一个连接产生了一个不可恢复的错误,必须立刻从连接池中去掉,否则会连续产生大量错误。这个特性,目前只有JBossDataSource和Druid实现。Druid的实现参考自JBossDataSource,经过长期生产反馈补充。
总结来看,Druid由于是阿里自用的数据库连接池,充分参考了各家武林门派的长处,尤其针对oracle做了大量优化,实在是居家编程,数据库连接的大杀器,下面是实际测试通过的Druid支持的数据库列表。
数据库 | 支持状态 |
mysql | 支持,大规模使用 |
oracle | 支持,大规模使用 |
sqlserver | 支持 |
postgres | 支持 |
db2 | 支持 |
h2 | 支持 |
derby | 支持 |
sqlite | 支持 |
sybase | 支持 |
针对springboot,阿里特地编写了与之更完美契合的druid,命名为:druid-spring-boot-starter
Druid 的监控数据可以通过 DruidStatManagerFacade 进行获取,获取到监控数据之后你可以将其暴露给你的监控系统进行使用。Druid 默认的监控系统数据也来源于此。
三、fastjson介绍
fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。
fastjson优点:速度快、使用广泛(阿里自己用)、测试更新频繁、使用简便
fastjson的API十分简洁。
String text = JSON.toJSONString(obj); //序列化
VO vo = JSON.parseObject("{...}", VO.class); //反序列化
支持泛型,支持流处理超大文本,支持枚举,支持序列化和反序列化扩展。
四、整合具体步骤
1、项目的pom.xml中新增对Druid、fastjson的引用依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
2、修改项目属性文件application.properties,新增对Druid与fastjson的专属配置内容
a、Druid配置内容
#Druid连接池配置
spring.datasource.druid.initialSize=5
spring.datasource.druid.minIdle=5
spring.datasource.druid.maxActive=30
######Druid监控配置######
#是否启用StatFilter默认值true
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.filter.log4j2.statement-log-enabled=true
#IP 白名单
spring.datasource.druid.stat-view-servlet.allow=133.3.5.71
#IP 黑名单
#spring.datasource.druid.stat-view-servlet.deny=192.168.0.101
#监控地址,默认 /druid/*
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
#哪些资源配置监控:主要只静态资源和监控地址本身
spring.datasource.druid.WebStatFilter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
spring.datasource.druid.stat-view-servlet.login-username=wangli
spring.datasource.druid.stat-view-servlet.login-password=123456
# 配置StatFilter
spring.datasource.druid.filter.stat.db-type=mysql
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=2000
# 配置WallFilter
spring.datasource.druid.filter.wall.enabled=true
spring.datasource.druid.filter.wall.db-type=mysql
spring.datasource.druid.filter.wall.config.delete-allow=false
spring.datasource.druid.filter.wall.config.drop-table-allow=false
上面这些配置分别定义了连接池属性、Druid自身访问安全限制,监控资源类型及开通了状态监控及sql防火墙监控,用于使用Druid的扩展功能。netstat -nao | find "3306"
上面定义的连接池默认连接数为5,所以在应用服务器上与数据库服务器的连接也就是5个,如上图。
b、fastjson配置内容
#fastjson配置
spring.http.converters.preferred-json-mapper=fastjson
#加入fastjson后需要配置否则json输出乱码
spring.http.encoding.force=true
3、通过Controller中增加入口加载Druid
import com.alibaba.druid.stat.DruidStatManagerFacade;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DruidStatController {
@GetMapping("/druid/stat")
public Object druidStat(){
// DruidStatManagerFacade#getDataSourceStatDataList
// 该方法可以获取所有数据源的监控数据,除此之外 DruidStatManagerFacade 还提供了一些其他方法,你可以按需选择使用。
return DruidStatManagerFacade.getInstance().getDataSourceStatDataList();
}
}
4、将fastjson的加载代码注入项目启动文件中
@SpringBootApplication
public class InfoApplication {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
//1.需要定义一个Convert转换消息的对象
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
//2.添加fastjson的配置信息,比如是否要格式化返回的json数据
FastJsonConfig fastJsonConfig = new FastJsonConfig();
// fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty);
fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
SerializerFeature.WriteEnumUsingToString,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.DisableCircularReferenceDetect);
//3.在convert中添加配置信息
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
public static void main(String[] args) {
SpringApplication.run(InfoApplication.class, args);
}
}
5、修改IpbaseDao接口,将原来返回String的findbyipadd接口的返回类型修改为实体类,实现通过IP地址查询时返回为实体类后被fastjson拦截后转为JSON代码
import javax.transaction.Transactional;
import java.util.List;
@Transactional
public interface IpbaseDao extends CrudRepository<Ipbase, Long> {
public Ipbase findByIpadd(String ipadd);
@Override
List<Ipbase> findAll();
}
6、修改ipcontroller文件,将原来的findip方法进行修改,配合第五步的成果
@RequestMapping(value = "/getipinfo", produces = "text/html;charset=UTF-8", method = RequestMethod.GET)
public Ipbase findip(String ip, HttpServletRequest request) {
if (ip != null) {
return ipbaseDao.findByIpadd(ip);
} else {
return ipbaseDao.findByIpadd(request.getRemoteAddr());
}
}
@RequestMapping(value = "/getall")
public List<Ipbase> getall() {
return ipbaseDao.findAll();
}
五、整合效果
1、输入指定ip地址查询返回JSON结果
http://133.3.5.71:8080/getipinfo?ip=202.103.44.150
{"city":"武汉","country":"中国","id":2,"ipadd":"202.103.44.150","isp":"电信","privince":"湖北"}
2、无输入参数返回JSON结果
http://133.3.5.71:8080/getipinfo
{"city":"武汉","country":"中国","id":1,"ipadd":"133.3.5.71","isp":"电信","privince":"湖北"}
3、返回全部ip列表JSON格式
[{"city":"武汉","country":"中国","id":1,"ipadd":"133.3.5.71","isp":"电信","privince":"湖北"},{"city":"武汉","country":"中国","id":2,"ipadd":"202.103.44.150","isp":"电信","privince":"湖北"}]
4、访问Druid监控界面必须要输入前面在application属性文件中定义的用户名密码,且ip地址是133.3.5.71才能登录
http://133.3.5.71:8080/druid/login.html
5、查看Druid-JSON-API的版本情况
6、查看Druid数据源详细信息
7、查看Druid的sql监控信息,之前我执行了两次查询,这里的监控马上更新自动显示
8、sql防火墙功能展示,自动识别业务系统操作的数据表,对sql语句进行识别
9、URI监控统计分析,通过观察URI的详细统计数据找出业务中存在问题的短板
六、总结回顾
使用阿里制作的成熟轮子可以迅速将我们不成熟的业务推向应用,互联网时代的业务很多都是尝试性的进入,没有那么多的时间和成本去试错,学习了解这些成熟的轮子,把自己有限的精力放在业务逻辑的实现上是最好的选择。
mysql每个连接是会创建一个线程的,可以登录mysql输入show status查看Threads_connected和Threads_created的大小,那么我们每连接一次mysql就会创建一个线程,每次断开又会销毁一个线程。创建线程和销毁线程的资源消耗是非常大的,不然也不会有线程池这个东西。
连接池避免了频繁的创建连接和销毁连接,内部避免了频繁的创建线程和销毁线程,其次mysql数据库会为每个连接分配连接缓冲区和结果缓冲区,也是要消耗时间的。
数据库连接池技术的思想非常简单,将数据库连接作为对象存储在一个Vector对象中,一旦数据库连接建立后,不同的数据库访问请求就可以共享这些连接,这样,通过复用这些已经建立的数据库连接,可以克服上述缺点,极大地节省系统资源和时间。