Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Handwritten database connection pool

2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)06/01 Report--

1. I believe many people already know what connection pooling is used for after reading this article. Yes, database connection pool is to establish a "buffer pool" for database connections, put a certain number of connections in the "buffer pool" in advance, and take one out of the "buffer pool" when you need to establish a database connection. Put it in after use. The advantage of this is that frequent database connections can avoid taking up a lot of system resources.

two。 Common database connection pools are: dbcp,c3p0, Ali's Druid. Well, without much gossip, this article aims to deepen your understanding of connection pooling. The database I chose here is mysql.

3. Let's first talk about the process of connection pooling:

First of all, there must be a configuration file! When we use data sources in our daily projects, we need to configure database drivers, database usernames, database passwords, and connections. These four roles are absolutely indispensable.

I believe many people already know what connection pooling is used for after reading this article. Yes, database connection pool is to establish a "buffer pool" for database connections, put a certain number of connections in the "buffer pool" in advance, and take one out of the "buffer pool" when you need to establish a database connection. Put it in after use. The advantage of this is that frequent database connections can avoid taking up a lot of system resources.

Common database connection pools are: dbcp,c3p0, Ali's Druid. Well, without much gossip, this article aims to deepen your understanding of connection pooling. The database I chose here is mysql.

Let's first talk about the process of connection pooling:

First of all, there must be a configuration file! When we use data sources in our daily projects, we need to configure database drivers, database usernames, database passwords, and connections. These four roles are absolutely indispensable.

# File name: db.properties

Jdbc.driver=com.mysql.jdbc.Driver

Jdbc.url=jdbc:mysql://localhost:3306/ssm

Jdbc.username=root

Jdbc.password=lfdy

Jdbc.initSize=3

Jdbc.maxSize=10

# whether to start the check

Jdbc.health=true

# check delay time

Jdbc.delay=3000

# interval

Jdbc.period=3000

Jdbc.timeout=100000

two。 We will write a class based on the above configuration file db.properties and load its properties

Public class GPConfig {

Private String driver

Private String url

Private String username

Private String password

Private String initSize

Private String maxSize

Private String health

Private String delay

Private String period

Private String timeout

/ / omit the set and get methods / / write a constructor to initialize properties in the constructor

Public GPConfig () {

Properties prop = new Properties ()

/ / this seems to be the only way to read files in a maven project.

InputStream stream = this.getClass () .getResourceAsStream ("/ resource/db.properties")

Try {

Prop.load (stream)

/ / call the setter method in the constructor. There are many attributes here, so we certainly do not call it step by step. It is recommended to use the reflection mechanism.

For (Object obj: prop.keySet ()) {

/ / get the parameter, how to get it? Isn't this the key removal of the configuration file? what should be removed? Remove "jdbc."

String fieldName = obj.toString () .replace ("jdbc.")

Field field = this.getClass () .getDeclaredField (fieldName)

Method method = this.getClass () .getMethod (toUpper (fieldName), field.getType ())

Method.invoke (this, prop.get (obj))

}

} catch (Exception e) {

E.printStackTrace ()

}

}

/ / read the key in the configuration file and convert it to the correct set method

Public String toUpper (String fieldName) {

Char [] chars = fieldName.toCharArray ()

Chars [0]-= 32; / / how to capitalize the first letter of a string

Return "set" + new String (chars)

}

}

3. All right, we've written the configuration file, and the class that loads the configuration file has been written. What's next? Recall that before we had a connection pool, did we use Class.forName (), getConnection, and so on to connect to the database? So, let's next write a class with methods to create a connection and get a connection.

Public class GPPoolDataSource {

/ / load configuration class

GPConfig config = new GPConfig ()

/ / write a parameter to mark how many active connections there are currently

Private AtomicInteger currentActive = new AtomicInteger (0)

/ / create a collection, for what? It is used to store connections. After all, we need to create initSize connections when we initialize them.

/ and, when we release the connection, we put the connection in here.

Vector freePools = new Vector ()

/ / connection pool in use

Vector usePools = new Vector ()

/ / initialization in the constructor

Public GPPoolDataSource () {

Init ()

}

/ / initialization method

Public void init () {

Try {

/ / do we have to load jdbc every time? Definitely not. Just load it once.

Class.forName (config.getDriver ())

For (int I = 0; I

< Integer.valueOf(config.getInitSize());i++){ Connection conn = createConn(); freePools.add(conn); } } catch (ClassNotFoundException e) { e.printStackTrace(); } check(); } //创建连接 public synchronized Connection createConn(){ Connection conn = null; try { conn = DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPassword()); currentActive.incrementAndGet(); System.out.println("创建一个连接, 当前的活跃的连接数目为:"+ currentActive.get()+" 连接:"+conn); } catch (SQLException e) { e.printStackTrace(); } return conn; } /** * 创建连接有了,是不是也应该获取连接呢? * @return */ public synchronized GPPoolEntry getConn(){ Connection conn = null; if(!freePools.isEmpty()){ conn = freePools.get(0); freePools.remove(0); }else{ if(currentActive.get() < Integer.valueOf(config.getMaxSize())){ conn = createConn(); }else{ try { System.out.println("连接池已经满了,需要等待..."); wait(1000); return getConn(); } catch (InterruptedException e) { e.printStackTrace(); } } } GPPoolEntry poolEntry = new GPPoolEntry(conn, System.currentTimeMillis()); //获取连接干嘛的?不就是使用的吗?所以,每获取一个,就放入正在使用池中 usePools.add(poolEntry); return poolEntry; } /** * 创建连接,获取连接都已经有了,接下来就是该释放连接了 */ public synchronized void release(Connection conn){ try { if(!conn.isClosed() && conn != null){ freePools.add(conn); } System.out.println("回收了一个连接,当前空闲连接数为:"+freePools.size()); } catch (SQLException e) { e.printStackTrace(); } } //定时检查占用时间超长的连接,并关闭 private void check(){ if(Boolean.valueOf(config.getHealth())){ Worker worker = new Worker(); new java.util.Timer().schedule(worker, Long.valueOf(config.getDelay()), Long.valueOf(config.getPeriod())); } } class Worker extends TimerTask{ @Override public void run() { System.out.println("例行检查..."); for(int i = 0; i < usePools.size();i++){ GPPoolEntry entry = usePools.get(i); long startTime = entry.getUseStartTime(); long currentTime = System.currentTimeMillis(); if((currentTime-startTime)>

Long.valueOf (config.getTimeout ()) {

Connection conn = entry.getConn ()

Try {

If (conn! = null & &! conn.isClosed ()) {

Conn.close ()

UsePools.remove (I)

CurrentActive.decrementAndGet ()

System.out.println ("timeout connection found, forcibly closed, current active connections:" + currentActive.get ())

}

} catch (SQLException e) {

E.printStackTrace ()

}

}

}

}

}

}

4. In the check () method above, to check for timeouts, we need to use a wrapper class

Public class GPPoolEntry {

Private Connection conn

Private long useStartTime

Public Connection getConn () {

Return conn

}

Public void setConn (Connection conn) {

This.conn = conn

}

Public long getUseStartTime () {

Return useStartTime

}

Public void setUseStartTime (long useStartTime) {

This.useStartTime = useStartTime

}

Public GPPoolEntry (Connection conn, long useStartTime) {

Super ()

This.conn = conn

This.useStartTime = useStartTime

}

}

5. All right, everything is ready. Let's write a test class and test it.

Public class GPDataSourceTest {

Public static void main (String [] args) {

GPPoolDataSource dataSource = new GPPoolDataSource ()

Runnable runnable = ()-> {

Connection conn = dataSource.getConn () .getConn ()

System.out.println (conn)

}

ExecutorService executorService = Executors.newFixedThreadPool (5)

For (int I = 0; I

< 60; i++) { executorService.submit(runnable); } executorService.shutdown(); } } 4.好了,我给下我的结果: 5.总结下,这个手写连接池部分,其实我也是学习的别人的,所以有很多东西不熟悉,也有许多漏洞,现在我先说下我需要完善的地方: 反射机制 读取properties文件 线程池 线程 集合Vector

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report