Druid (Druid) database connection pool

1. The necessity of database connection pool

(1). Steps of the traditional database connection mode

  1. Create a connection in the main program
  2. Perform sql operations
  3. close database connection

(2). Problems in the traditional database connection mode

  1. Waste of time: verify login and load connection into memory every time you connect,

  2. Unable to access the database on a large scale: When there are too many database visitors, it will take up a lot of system resources and cause the server to crash

  3. There is a memory leak problem: each connection needs to be disconnected. If it is not disconnected, the program will end, and the created connection object will remain in memory and cannot be closed, which will cause java memory leaks.

Memory leak : means that the created object cannot be recycled

2. Database connection pool technology

(1). The idea of ​​data connection pool:

Create a buffer pool in memory in advance to store a certain number of connection objects, call it when needed, and put it back into the buffer pool at the end.

(2). The tasks of the database connection pool:

Manage and release database connections, allowing users to use connection objects in the pool without creating objects.

(3). The size of the database connection pool:

Number at initialization: set by the minimum number of database connections;

Maximum number: Determined by the maximum number of database connections.

When the number of connections exceeds the maximum number of connections, the excess connections will stop waiting for the connection object to be released.

(4). Working principle:

insert image description here

(5). Advantages of database connection pool:

  1. Resource reuse:
    Objects in the connection pool are taken out when needed, and do not need to be recycled by the connection pool

  2. Faster response speed:
    the connection object is reserved in the pool in advance, the initialization has been completed, and the call is made directly.

  3. Database sharing mechanism
    When multiple users access the same database, resource monopoly can be avoided through configuration at the application layer.

  4. Avoid memory leaks:
    unified management of connection objects, setting time slices of connection objects, and forced recycling when timeout occurs.

3. A variety of open source database connection pools

The JDBC database connection pool is represented by javax.sql.DataSource,DataSourceis an interface, which is usually provided by the server.

Common open source database connection pools:

DBCP: faster than C3P0 but has bugs

c3p0: slow, but relatively stable

Proxool: open source connection pool, has the function of monitoring connection pool, but the stability is worse than C3P0

BoneCP: fast, open source

Druid: The connection pool provided by Ali is fast (not as good as BoneCP), good in stability, and has the function of monitoring the connection pool.

4. Learn the most mainstream database connection pool Druid

Druid is a database connection pool provided by Ali. It is said to be a database connection pool that combines the advantages of DBCP, C3P0 and Proxool. It is currently the most used database connection pool technology in China.

(1). Create a connection (configuration file method)

  • rely
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>

        <dependency>
        <!--mysql版本对应-->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
  • Configuration file
    Create a configuration file druid.propertiesand enter configuration information
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=12345678
initialSize=10
maxActive=20
  • Detailed configuration parameters
configuration default illustrate
name The significance of configuring this property is that if there are multiple data sources, they can be distinguished by name during monitoring. If not configured, a name will be generated in the format: "DataSource-" + System.identityHashCode(this)
url The url to connect to the database is different for different databases. For example: mysql: jdbc:mysql://10.20.153.104:3306/druid2 oracle: jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username The username to connect to the database
password Password to connect to the database. If you don't want the password to be written directly in the configuration file, you can use ConfigFilter. See here for details: https://github.com/alibaba/druid/wiki/Using ConfigFilter
driverClassName According to the automatic identification of the url, this item can be configured or not. If you do not configure druid, it will automatically identify the dbType according to the url, and then select the corresponding driverClassName (recommended configuration)
initialSize 0 The number of physical connections established during initialization. Initialization occurs when the init method is called explicitly, or when getConnection is first
maxActive 8 Maximum number of connection pools
maxIdle 8 It is no longer used, and the configuration has no effect
minIdle Minimum number of connection pools
maxWait The maximum waiting time when obtaining a connection, in milliseconds. After maxWait is configured, the fair lock is enabled by default, and the concurrency efficiency will decrease. If necessary, you can use the unfair lock by configuring the useUnfairLock attribute to true.
poolPreparedStatements false Whether to cache preparedStatement, that is, PSCache. PSCache greatly improves the performance of databases that support cursors, such as oracle. It is recommended to close it under mysql.
maxOpenPreparedStatements -1 To enable PSCache, it must be configured to be greater than 0. When it is greater than 0, poolPreparedStatements will be automatically triggered and changed to true. In Druid, there will be no problem of PSCache occupying too much memory under Oracle. You can configure this value to be larger, for example, 100
validationQuery The sql used to check whether the connection is valid requires a query statement. If validationQuery is null, testOnBorrow, testOnReturn, and testWhileIdle will not work.
testOnBorrow true When applying for a connection, execute validationQuery to check whether the connection is valid. Doing this configuration will reduce performance.
testOnReturn false Execute validationQuery to check whether the connection is valid when returning the connection. Doing this configuration will reduce performance
testWhileIdle false It is recommended to configure it as true, which will not affect performance and ensure security. Check when applying for a connection. If the idle time is greater than timeBetweenEvictionRunsMillis, execute validationQuery to check whether the connection is valid.
timeBetweenEvictionRunsMillis There are two meanings: 1) The Destroy thread will detect the connection interval 2) The judgment basis of testWhileIdle, see the description of the testWhileIdle attribute for details
numTestsPerEvictionRun No longer used, a DruidDataSource only supports one EvictionRun
minEvictableIdleTimeMills
connectionInitSqls The sql executed when the physical connection is initialized
exceptionSorter Automatically identify according to dbType when the database throws some unrecoverable exceptions, discard the connection
filters The attribute type is a string, and the extension plug-in is configured through an alias. Commonly used plug-ins include: filter for monitoring statistics: filter for stat logs: log4j filter for preventing SQL injection: wall
proxyFilters The type is List. If filters and proxyFilters are configured at the same time, it is a combination relationship, not a replacement relationship
  • Encapsulation connection tool class
public class DruidUtils {
    
    

    private static DataSource source;

    /**
     * 静态代码块中加载配置文件,随着类的加载而执行
     */
    static {
    
    
        try {
    
    
            //创建properties对象,用来封装从文件中获取的流数据
            Properties pros = new Properties();
            //采用类加载方式获取文件的内容,并封装成流
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("Druid.properties");
            //将流传入到pros对象中
            pros.load(is);
            //利用工厂类创建数据库连接池
            source = DruidDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 获取连接  直接使用数据库连接池对象条用getConnection()方法
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
    
    
        return source.getConnection();
    }

    /**
     * 关闭连接
     * @param connection
     * @param stm
     * @param rs
     */
    public static void close(Connection connection, Statement stm, ResultSet rs) {
    
    
        try {
    
    
            if (connection != null) connection.close();
        } catch (Exception throwable) {
    
    
            throwable.printStackTrace();
        }
        try {
    
    
            if (stm != null) stm.close();
        } catch (Exception throwable) {
    
    
            throwable.printStackTrace();
        }
        try {
    
    
            if (rs != null) rs.close();
        } catch (Exception throwable) {
    
    
            throwable.printStackTrace();
        }
    }

    /**
     * 重载close方法
     */
    public static void close(Connection conn, Statement stm) {
    
    
        close(conn, stm, null);
    }

}
  • test class
    /**
     * 测试连接是否成功
     * @throws Exception
     */
    @Test
    public void getDruidConnection() throws Exception {
    
    
        Connection conn = DruidUtils.getConnection();
        System.out.println(conn);
    }

The return value is as follows, the connection is successful
insert image description here

Simple CRUD

  • Entity class
public class ApplicationDO {
    
    
    /**
     * 主键ID
     */
    private Long id;

    /**
     * 申请类型 0 未知,1 license,2 soultion,3 both
     */
    private Integer applyType;


    /**
     * teamwork项目名称
     */
    private String teamworkProjectName;

    /**
     * 项目名称
     */
    private String projectName;


    /**
     * 客户名称
     */
    private String customName;


    /**
     * 获取主键ID
     *
     * @return id - 主键ID
     */
    public Long getId() {
    
    
        return id;
    }

    /**
     * 设置主键ID
     *
     * @param id 主键ID
     */
    public void setId(Long id) {
    
    
        this.id = id;
    }

    /**
     * 获取申请类型 0 未知,1 license,2 soultion,3 both
     *
     * @return apply_type - 申请类型 0 未知,1 license,2 soultion,3 both
     */
    public Integer getApplyType() {
    
    
        return applyType;
    }

    /**
     * 设置申请类型 0 未知,1 license,2 soultion,3 both
     *
     * @param applyType 申请类型 0 未知,1 license,2 soultion,3 both
     */
    public void setApplyType(Integer applyType) {
    
    
        this.applyType = applyType;
    }


    /**
     * 获取teamwork项目名称
     *
     * @return teamwork_project_name - teamwork项目名称
     */
    public String getTeamworkProjectName() {
    
    
        return teamworkProjectName;
    }

    /**
     * 设置teamwork项目名称
     *
     * @param teamworkProjectName teamwork项目名称
     */
    public void setTeamworkProjectName(String teamworkProjectName) {
    
    
        this.teamworkProjectName = teamworkProjectName;
    }

    /**
     * 获取项目名称
     *
     * @return project_name - 项目名称
     */
    public String getProjectName() {
    
    
        return projectName;
    }

    /**
     * 设置项目名称
     *
     * @param projectName 项目名称
     */
    public void setProjectName(String projectName) {
    
    
        this.projectName = projectName;
    }


    /**
     * 获取客户名称
     *
     * @return custom_name - 客户名称
     */
    public String getCustomName() {
    
    
        return customName;
    }

    /**
     * 设置客户名称
     *
     * @param customName 客户名称
     */
    public void setCustomName(String customName) {
    
    
        this.customName = customName;
    }


    @Override
    public String toString() {
    
    
        return "ApplicationDO{" +
                "id=" + id +
                ", applyType=" + applyType +
                ", teamworkProjectName='" + teamworkProjectName + '\'' +
                ", projectName='" + projectName + '\'' +
                ", customName='" + customName + '\'' +
                '}';
    }
}
  • CRUD
/**
     * 查询
     * @throws Exception
     */
    @Test
    public void Select() throws Exception {
    
    
        //因为获取连接创建的是静态方法  直接使用类名.方法名调取  获得连接即可
        Connection conn= DruidUtils.getConnection();
        String sql="SELECT * FROM licenx_application";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        ResultSet rs = pstmt.executeQuery();
        ApplicationDO applicationDO;
        List<ApplicationDO> applicationDOs=new ArrayList<>();
        //遍历ResultSet结果集  存入List
        while (rs.next()){
    
    
            applicationDO=new ApplicationDO();
            applicationDO.setId(rs.getLong("id"));
            applicationDO.setCustomName(rs.getString("custom_name"));
            applicationDO.setApplyType(rs.getInt("apply_type"));
            applicationDO.setTeamworkProjectName(rs.getString("teamwork_project_name"));
            applicationDO.setProjectName(rs.getString("project_name"));
            applicationDOs.add(applicationDO);

        }
        //输出list查看
        for (ApplicationDO applicationDO1 : applicationDOs) {
    
    
            System.out.println(applicationDO1);
        }

        DruidUtils.close(conn,pstmt,rs);
    }


    /**
     * 插入
     * @throws Exception
     */
    @Test
    public void insert() throws Exception {
    
    
        //获取数据库连接
        Connection conn=DruidUtils.getConnection();
        String sql="insert into licenx_application (custom_name, apply_type, teamwork_project_name, project_name) values (?, ?, ?, ?)";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //设置sql语句中的?值
        pstmt.setObject(1,"测试");
        pstmt.setObject(2,1);
        pstmt.setObject(3,"测试");
        pstmt.setObject(4,"测试");
        int i = pstmt.executeUpdate();
        if (i>0){
    
    
            System.out.println("添加成功");
        }
        //释放资源
        DruidUtils.close(conn,pstmt);
    }


    /**
     * 删除
     * @throws Exception
     */
    @Test
    public void delete() throws Exception {
    
    
        //获取连接
        Connection conn=DruidUtils.getConnection();
        String sql="DELETE from licenx_application where id=?";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //设置sql中的?值
        pstmt.setObject(1,251757598242504708l);
        int i = pstmt.executeUpdate();
        if (i>0) System.out.println("删除成功");
        //关闭资源
        DruidUtils.close(conn,pstmt);

    }


    /**
     * 更新
     * @throws Exception
     */
    @Test
    public void update() throws Exception {
    
    
        //获取连接
        Connection conn=DruidUtils.getConnection();
        String sql="UPDATE licenx_application SET teamwork_project_name=? WHERE id=?";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //设置sql中?的值
        pstmt.setObject(1,"99999");
        pstmt.setObject(2,251757598242504706l);
        int i = pstmt.executeUpdate();
        if (i>0) System.out.println("修改成功");
        //释放资源
        DruidUtils.close(conn,pstmt);

    }

Guess you like

Origin blog.csdn.net/doublepg13/article/details/128849335