当前位置: 首页 > 工具软件 > fast-dao > 使用案例 >

dao连接mysql数据库引擎_手写DAO框架(三)-数据库连接

呼延靖
2023-12-01

-------前篇:手写DAO框架(二)-开发前的最后准备---------

前言

上一篇主要是温习了一下基础知识,然后将整个项目按照模块进行了划分。因为是个人项目,一个人开发,本人采用了自底向上的开发。

本篇会介绍连接层的代码,包括三部分:pom配置、数据库连接和数据库连接池。

pom配置

1

2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

3 4.0.0

4

5 me.lovegao

6 gdao

7 0.0.2-SNAPSHOT

8 jar

9

10 gdao

11 http://maven.apache.org

12

13

14 UTF-8

15 4.12

16

17

18

19

20 junit

21 junit

22 ${junit.version}

23 test

24

25

26 org.slf4j

27 slf4j-api

28 1.7.12

29

30

31 com.alibaba

32 fastjson

33 1.2.31

34

35

36 org.apache.commons

37 commons-lang3

38 3.2.1

39

40

41 mysql

42 mysql-connector-java

43 5.1.31

44

45

46

47 me_lovegao_gdao

48

49

50 org.apache.maven.plugins

51 maven-compiler-plugin

52 3.7.0

53

54 1.8

55 1.8

56

57

58

59

60

maven定义了jdk的版本,免得导入IDE的时候变成1.5,又得修改。

数据库连接

数据库连接主要就是为了获取数据库连接,这个模块不关注连接的使用、关闭等,只提供获取连接,其他逻辑由调用方负责。

书上、网上都说,要面向接口编程。

本来我是定义了一个接口的,但是最终实现的时候没有用上。回头看这段代码,感觉用上接口之后,依赖关系有点复杂,所以就没改了。

而且,这里的获取连接,定位的是一个工具类,所以直接写了静态方法。

1、连接获取类:ConnectionGetor

1 packageme.lovegao.gdao.connection;2

3 importjava.sql.Connection;4 importjava.sql.DriverManager;5 importjava.util.Properties;6

7 importorg.slf4j.Logger;8 importorg.slf4j.LoggerFactory;9

10 importme.lovegao.gdao.bean.SystemConstant;11

12 public classConnectionGetor {13 private final static Logger log = LoggerFactory.getLogger(ConnectionGetor.class);14

15 public static Connection createConnection(Properties properties) throwsException {16 Connection conn = null;17 String driverName =properties.getProperty(SystemConstant.STR_DRIVER_NAME);18 String url =properties.getProperty(SystemConstant.STR_CONNECTION_URL);19 String userName =properties.getProperty(SystemConstant.STR_USER_NAME);20 String passwd =properties.getProperty(SystemConstant.STR_USER_PASSWORD);21 try{22 Class.forName(driverName);23 conn =DriverManager.getConnection(url, userName, passwd);24 } catch(Exception e) {25 log.error("createConnectionException", e);26 }27 returnconn;28 }29

30 }

为了保证通用性,入参我选择了Properties类型。这样,配置既可以从本地加载,也可以从流加载,确保了灵活性。

为了能够支持多数据源,所以这个方法里没有定义和数据库连接相关的局部变量或者常量。

2、数据库实例配置:Properties

说到了配置,我就把配置的字段先列一下。毕竟框架再好用,不教人怎么配置就是扯。

##驱动名称

driverName=com.mysql.jdbc.Driver

##连接url

connectionUrl=jdbc:mysql://localhost:3306/simple?useServerPrepStmts=false&rewriteBatchedStatements=true&connectTimeout=1000&useUnicode=true&characterEncoding=utf-8

##用户名

userName=name

##用户密码

userPassword=123456

##初始化连接数

initConnectionNum=10

##最大连接数

maxConnectionNum=50

##最大查询等待时间-秒

maxQueryTime=3

配置这块就是这样的。为什么定义了这几个配置,在前两篇文章里也有涉及,这里不再赘述。

数据库连接池

因为数据库连接的创建是需要时间的,我们可以在项目初始化的时候先创建一批连接,在需要使用连接的时候可以节省创建连接的等待时间,从而提高程序响应速度。而且,连接是可以复用的,所以,项目中使用连接池是有意义的。

要面向接口编程,所以这里先定义接口。

1、连接池接口:IConnectionPool

1 packageme.lovegao.gdao.connection;2

3 importjava.sql.Connection;4

5 /**

6 * 连接池7 *@authorsimple8 *9 */

10 public interfaceIConnectionPool {11 /**

12 * 获取连接13 *@return

14 */

15 Connection getConnection() throwsException;16 /**

17 * 归还连接18 *@paramconn19 */

20 voidreturnConnection(Connection conn);21

22 /**

23 * 获取查询超时时间24 *@return

25 */

26 intgetQueryTimeoutSecond();27 }

从代码可以看到,连接池的主要功能包括:获取连接,归还连接。

“获取查询超时时间”这个接口是我后来加的,作为一个框架,应该保证不因为一个查询耗时超过正常区间仍然义无反顾的等待。只不过加在这里,感觉不太优雅,暂时也没有想到更好的写法,所以还是暂时放在这里吧。(有建议欢迎提出)

2、连接池的简单实现:SimpleConnectionPool

1 packageme.lovegao.gdao.connection;2

3 importjava.sql.Connection;4 importjava.util.Map;5 importjava.util.Properties;6 importjava.util.Queue;7 importjava.util.concurrent.ConcurrentHashMap;8 importjava.util.concurrent.ConcurrentLinkedQueue;9 importjava.util.concurrent.atomic.AtomicInteger;10

11 importorg.slf4j.Logger;12 importorg.slf4j.LoggerFactory;13

14 importme.lovegao.gdao.bean.SystemConstant;15

16 public class SimpleConnectionPool implementsIConnectionPool {17 private final static Logger log = LoggerFactory.getLogger(SimpleConnectionPool.class);18 /**配置**/

19 privateProperties properties;20 /**保存连接的map**/

21 private final Map CONNECTION_MAP_POOL = newConcurrentHashMap();22 /**连接池的连接索引**/

23 private final Queue CONNECTION_KEY_POOL = newConcurrentLinkedQueue();24 /**连接池初始连接数量**/

25 private intPOOL_INIT_NUM;26 /**连接池最大连接数量**/

27 private intPOOL_MAX_NUM;28 /**已创建连接数量**/

29 private AtomicInteger POOL_CREATE_NUM = new AtomicInteger(0);30 /**查询超时时间-秒**/

31 private intQUERY_TIMEOUT_SECONDS;32

33 public SimpleConnectionPool(Properties properties) throwsException {34 this.properties =properties;35 this.POOL_INIT_NUM =Integer.parseInt(properties.getProperty(SystemConstant.STR_INIT_CONNECTION_NUM));36 this.POOL_MAX_NUM =Integer.parseInt(properties.getProperty(SystemConstant.STR_MAX_CONNECTION_NUM));37 this.QUERY_TIMEOUT_SECONDS =Integer.parseInt(properties.getProperty(SystemConstant.STR_QUERY_TIME));38 for(int i=0; i

46 @Override47 public Connection getConnection() throwsException {48 Connection conn = null;49 Integer connKey =CONNECTION_KEY_POOL.poll();50 if(connKey == null) {51 if(POOL_CREATE_NUM.intValue()

64 if(conn == null) {65 throw new NullPointerException("连接池连接用完");66 }67 returnconn;68 }69

70 @Override71 public voidreturnConnection(Connection conn) {72 if(conn != null) {73 try{74 if(conn.isClosed()) {75 CONNECTION_MAP_POOL.remove(conn.hashCode());76 POOL_CREATE_NUM.decrementAndGet();77 } else{78 CONNECTION_KEY_POOL.add(conn.hashCode());79 }80 } catch(Exception e) {81 log.error("returnConnectionException", e);82 }83 }84 }85

86 @Override87 public intgetQueryTimeoutSecond() {88 returnQUERY_TIMEOUT_SECONDS;89 }90

91 }

逻辑简介:初始化的时候,先创建指定数量的连接存起来。在获取连接的时候,如果还有连接,就返回;如果没有连接了,就判断连接数是否到了最大上限,没有到就创建并返回,到上限了就返回空。

其他说明:

为了保证并发安全,这里是通过POOL_CREATE_NUM变量来保证的。

为了支持多数据源,这里同样没有静态变量。

为了保存连接,这里定义了两个容器,分别是Map CONNECTION_MAP_POOL和Queue CONNECTION_KEY_POOL。为了并发安全,使用了ConcurrentHashMap和ConcurrentLinkedQueue来存储。

其中,队列是用于取出连接和返回连接,这里队列存放的是连接对应的key。MAP是为了保存对所有连接的引用,防止一些连接没有归还而系统却不知道,同时也可以知道连接的总数。也有一点考虑,是为了以后可以有单独线程来定时判断哪些线程应该关闭,主要是为了以后扩展用。

最初,我想把连接池做成那种:获取连接的时候,如果没有连接,就等待一段时间(指定时间,即获取连接等待时间)之后再试。查了一下对应的技术栈,综合考虑了一下,感觉有些不足之处,比如:如果连接用完了,可能出现大量线程等待的现象,反而会影响性能。

后来参考了一下其他连接池的实现,最终做成目前的这样:获取连接的时候,没有连接,看能不能创建,能创建就创建,不能创建就返回失败。逻辑简单,容易实现,快速错误。大概这就是fast-fail吧!

--本文内容到这里就结束了,欢迎指导交流--

 类似资料: