精华内容
下载资源
问答
  • 使用一个mysql.ini文件(就是一个properties文件)来保存数据库连接信息,这是比较成熟的做法———但需要把应用程序 从开发环境移植到生产环境时,无须修改源代码,只需要修改mysql.ini配置文件即可。 凡凡第一看到...

    这里是使用mysql数据库。

    使用一个mysql.ini文件(就是一个properties文件)来保存数据库连接信息,这是比较成熟的做法———但需要把应用程序

    从开发环境移植到生产环境时,无须修改源代码,只需要修改mysql.ini配置文件即可。


    凡凡第一看到时候,以为是mysql.ini自带文件,就把mysql里的复制过去。(o(╯□╰)o囧了!!)


    下图展示文件及其存放位置。


    创建文件



    文件内容




    文件存放:

    ①与所要使用类的同级



    ②直接放在src下

    在web中放在src的配置文件会直接加载到classes中

    而Java的properties文件需要放到classpath下面,这样程序才能读取到,有关classpath实际上就是java类或者库的存放路径,在java工程中,properties放到class文件一块

    原因:读取文件是使用类加载器,而类加载器读取文件,默认是在src下。


    class文件一块

    操作:


    使用如下

    public class ExecuteDDL
    {
        private String driver;
        private String url;
        private String user;
        private String pwd;
        public void initParam(String paramFile) throws Exception
        {
    
            Properties props= new Properties();
            props.load(new FileInputStream(paramFile));
            driver = props.getProperty("driver");
            url = props.getProperty("url");
            user = props.getProperty("user");
            pwd = props.getProperty("pwd");
        }
        public void createTable(String sql) throws Exception
        {
    
            Class.forName(driver);
            try(
    
                    Connection conn = DriverManager.getConnection(url, user, pwd);
    
                    Statement stmt = conn.createStatement())
            {
    
                stmt.executeUpdate(sql);
            }
    
        }
        public static void main(String []args) throws Exception
        {
            ExecuteDDL ed = new ExecuteDDL();
            ed.initParam("src/com/yyf/JDBC/db.properties");
            ed.createTable("create table jdbc_test" +
                            "(jdbc_id int auto_increment primary key,"
                            +"jdbc_name varchar(255)"
                            +"jdbc_desc text);"
            );
            System.out.println("成功");
        }
    }




    展开全文
  • 通过数据库连接池的原理,结合并发队列,配置文件映射的知识点,尝试自己的连接池框架


    关于数据库连接池原理,什么杂七杂八的,本文不再重复啰嗦。有什么不理解的参考如下文章。
    阅读本文手写一套数据库连接池,您可能需要了解如下几个知识点:
    1、 数据库连接池的原理及作用
    2、 并发队列介绍及使用
    3、 配置文件properties信息映射到Java对象
    在我们配置连接池的时候,会配置一些数据,比如最小空闲连接数,最大空闲连接数等等,本文中,您需要理解如下几个概念。

    1、术语介绍

    空闲连接池:用来存放已经被创建,但是未被使用的连接的容器。
    活动连接池:用来存放已经被创建,并且被使用的连接的容器。
    最大空闲数:空闲连接池中,最多存在的空闲连接数量。
    初始化连接数:第一次加载的时候,需要创建的连接数量,一般大于最小空闲数,小于最大空闲数。
    最大连接数:空闲连接和活动连接之和。

    2、实现原理

    1、初始化:第一次加载的时候,根据配置的初始化连接数,创建连接,将创建的连接放入到空闲连接池;
    2、获取连接:优先从空闲池获取,如果空闲池没有,就创建一个新的连接
    在这里插入图片描述
    3、释放连接:将需要释放的连接从活动连接池中移除,如果空闲连接池没有满,放将移除的连接放入到空闲连接池,如果空闲连接池已经满了,则关闭此链接。

    3、代码实现

    代码结构如下
    在这里插入图片描述

    3.1连接池配置文件

    ##驱动名称:不推荐com.mysql.jdbc.Driver,而是推荐使用com.mysql.cj.jdbc.Driver
    driverName = com.mysql.cj.jdbc.Driver
    ##数据库连接地址
    url = jdbc:mysql://127.0.0.1:3306/test
    userName = root
    passWord = root
    ##连接池名字
    poolName = Hutao Connection Pool
    ##空闲池,最小连接数
    minFreeConnections = 1
    ##初始化空闲池连接数
    initFreeConnections = 3
    ##空闲池,最大连接数
    maxFreeConnections = 5
    ##最大允许的连接数,一般小于数据库总连接数
    maxConnections = 15
    ##重试获得连接的频率  一秒
    retryConnectionTimeOut = 1000
    ##连接超时时间,默认20分钟  1000 * 60 * 20
    connectionTimeOut = 1200000
    
    
    /**
     * @Description:数据库连接池属性信息
     * @author hutao
     * @mail hutao_2017@aliyun.com
     * @date 2020年07月08日
     */
    public class DbProperties {
    
    	/* 链接属性 */
    	private String driverName;
    
    	private String url;
    
    	private String userName;
    
    	private String passWord;
    
    	private String poolName;
    
    	/**
    	 * 空闲池,最小连接数
    	 */
    	private int minFreeConnections;
    
    	/**
    	 * 空闲池,最大连接数
    	 */
    	private int maxFreeConnections;
    
    	/**
    	 * 初始连接数
    	 */
    	private int initFreeConnections;
    
    	/**
    	 * 重试获得连接的频率  毫秒
    	 */
    	private long retryConnectionTimeOut;
    
    	/**
    	 * 最大允许的连接数
    	 */
    	private int maxConnections;
    
    	/**
    	 * 连接超时时间
    	 */
    	private long connectionTimeOut;
    
    	public String getDriverName() {
    		return driverName;
    	}
    
    	public void setDriverName(String driverName) {
    		this.driverName = driverName;
    	}
    
    	public String getUrl() {
    		return url;
    	}
    
    	public void setUrl(String url) {
    		this.url = url;
    	}
    
    	public String getUserName() {
    		return userName;
    	}
    
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    
    	public String getPassWord() {
    		return passWord;
    	}
    
    	public void setPassWord(String passWord) {
    		this.passWord = passWord;
    	}
    
    	public String getPoolName() {
    		return poolName;
    	}
    
    	public void setPoolName(String poolName) {
    		this.poolName = poolName;
    	}
    
    	public int getMinFreeConnections() {
    		return minFreeConnections;
    	}
    
    	public void setMinFreeConnections(int minFreeConnections) {
    		this.minFreeConnections = minFreeConnections;
    	}
    
    	public int getMaxFreeConnections() {
    		return maxFreeConnections;
    	}
    
    	public void setMaxFreeConnections(int maxFreeConnections) {
    		this.maxFreeConnections = maxFreeConnections;
    	}
    
    	public int getInitFreeConnections() {
    		return initFreeConnections;
    	}
    
    	public void setInitFreeConnections(int initFreeConnections) {
    		this.initFreeConnections = initFreeConnections;
    	}
    
    	public long getRetryConnectionTimeOut() {
    		return retryConnectionTimeOut;
    	}
    
    	public void setRetryConnectionTimeOut(long retryConnectionTimeOut) {
    		this.retryConnectionTimeOut = retryConnectionTimeOut;
    	}
    
    	public int getMaxConnections() {
    		return maxConnections;
    	}
    
    	public void setMaxConnections(int maxConnections) {
    		this.maxConnections = maxConnections;
    	}
    
    	public long getConnectionTimeOut() {
    		return connectionTimeOut;
    	}
    
    	public void setConnectionTimeOut(long connectionTimeOut) {
    		this.connectionTimeOut = connectionTimeOut;
    	}
    
    	@Override
    	public String toString() {
    		return "DbProperties [driverName=" + driverName + ", url=" + url + ", userName=" + userName + ", passWord="
    				+ passWord + ", poolName=" + poolName + ", minFreeConnections=" + minFreeConnections
    				+ ", maxFreeConnections=" + maxFreeConnections + ", initFreeConnections=" + initFreeConnections
    				+ ", retryConnectionTimeOut=" + retryConnectionTimeOut + ", maxConnections=" + maxConnections
    				+ ", connectionTimeOut=" + connectionTimeOut + "]";
    	}
    }
    
    

    3.2连接池管理

    import java.lang.reflect.Field;
    import java.lang.reflect.Type;
    import java.sql.Connection;
    import java.util.Enumeration;
    import java.util.ResourceBundle;
    
    import com.hutao.pool.database.pojo.DbProperties;
    import com.hutao.pool.database.service.DbPoolService;
    import com.hutao.pool.database.service.impl.DbPoolServiceImpl;
    
    /**
     * @Description:数据库连接池管理
     * @author hutao
     * @mail hutao_2017@aliyun.com
     * @date 2020年07月08日
     */
    public class DbPoolManager {
    	
    	private static String sourcePath = "com/hutao/resources/database";
    	
    	/**
    	 * 数据库连接池配置属性
    	 */
    	private static DbProperties properties = null;
    	
    	/**
    	 * 数据库连接池接口
    	 */
    	private static DbPoolService connectionPool = null;
    	
    	
    	/**
    	 * 双重检查机制静态加载连接池
    	 */
    	static {
    		try {
    			if(properties == null) {
    				synchronized(DbPoolManager.class) {
    					if(properties == null) {
    						properites2Object();
    						connectionPool = new DbPoolServiceImpl(properties);
    					}
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		
    	}
    	
    	/**
    	 * @Description:数据库连接池database配置文件映射到java对象
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月08日
    	 */
    	private static void properites2Object() throws NoSuchFieldException, IllegalAccessException {
    		properties = new DbProperties();
    		ResourceBundle resourceBundle = ResourceBundle.getBundle(sourcePath);
    		//获取资源文件中所有的key
    		Enumeration<String> keys = resourceBundle.getKeys();
    		while (keys.hasMoreElements()) {
    			String key = (String) keys.nextElement();
    			//反射获取类中的属性字段
    			Field field= DbProperties.class.getDeclaredField(key);
    			//属性字段的类型
    			Type genericType = field.getGenericType();
    			//属性设置可访问
    			field.setAccessible(true);
    			//根据key读取对应的value值
    			String value = resourceBundle.getString(key);
    			if("int".equals(genericType.getTypeName())) {
    				//反射给属性赋值
    				field.set(properties, Integer.parseInt(value));
    			}else if("long".equals(genericType.getTypeName())) {
    				field.set(properties, Long.parseLong(value));
    			}else if("java.lang.String".equals(genericType.getTypeName())) {
    				field.set(properties,value);
    			}
    		}
    	}
    	
    	/**
    	 * @Description:获取连接
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月09日
    	 */
    	public static Connection getConnection() {
    		return connectionPool.getConnection();
    	}
    
    	/**
    	 * @Description:释放连接
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月09日
    	 */
    	public static void releaseConnection(Connection connection) {
    		connectionPool.releaseConnection(connection);
    	}
    

    3.3连接池接口

    import java.sql.Connection;
    
    /**
     * @Description:数据库连接池
     * @author hutao
     * @mail hutao_2017@aliyun.com
     * @date 2020年07月08日
     */
    public interface DbPoolService {
    	
    	/**
    	 * @Description:判断连接是否可用,可用返回true
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月08日
    	 */
    	public boolean isAvailable(Connection connection);
    
    	/**
    	 * @Description:使用重复利用机制获取连接
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月08日
    	 */
    	public Connection getConnection();
    
    	/**
    	 * @Description:使用可回收机制释放连接
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月09日
    	 */
    	public void releaseConnection(Connection connection);
    }
    
    

    3.4连接池实现

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    
    import com.hutao.pool.database.pojo.DbProperties;
    import com.hutao.pool.database.service.DbPoolService;
    /**
     * @Description:数据库连接池实现
     * @author hutao
     * @mail hutao_2017@aliyun.com
     * @date 2020年07月09日
     */
    public class DbPoolServiceImpl implements DbPoolService {
    	
    	/**
    	 * 存放空闲连接的容器,除了可以使用并发队列,也可以使用线程安全的集合Vector
    	 */
    	private BlockingQueue<Connection> freeConnection = null;
    	/**
    	 * 存放活动连接的容器,除了可以使用并发队列,也可以使用线程安全的集合Vector
    	 */
    	private BlockingQueue<Connection> activeConnection = null;
    	
    	/**
    	 * 存放映射的属性配置文件
    	 */
    	private DbProperties dDbProperties;
    
    	
    	public DbPoolServiceImpl(DbProperties dDbProperties) throws Exception {
    		// 获取配置文件信息
    		this.dDbProperties = dDbProperties;
    		freeConnection =  new LinkedBlockingQueue<>(dDbProperties.getMaxFreeConnections());
    		activeConnection = new LinkedBlockingQueue<>(dDbProperties.getMaxConnections());
    		init();
    	}
    
    	/**
    	 * @Description:初始化空闲线程池
    	 * @author hutao
    	 * @throws Exception 
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月08日
    	 */
    	private void init() throws Exception {
    		System.out.println("初始化线程池开始,线程池配置属性:"+dDbProperties);
    		if (dDbProperties == null) {
    			throw new  Exception("连接池配置属性对象不能为空");
    		}
    		//获取连接池配置文件中初始化连接数
    		for (int i = 0; i < dDbProperties.getInitFreeConnections(); i++) {
    			//创建Connection连接
    			Connection newConnection = newConnection();
    			if (newConnection != null) {
    				//将创建的新连接放入到空闲池中
    				freeConnection.add(newConnection);
    			}
    		}
    		System.out.println("初始化线程池结束,初始化线程数:"+dDbProperties.getInitFreeConnections());
    	}
    
    	/**
    	 * @Description:
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月08日
    	 */
    	private synchronized Connection newConnection() {
    		try {
    			Class.forName(dDbProperties.getDriverName());
    			return DriverManager.getConnection(dDbProperties.getUrl(), dDbProperties.getUserName(),dDbProperties.getPassWord());
    		} catch (Exception e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    	
    	/**
    	 * @Description:判断连接是否可用,可用返回true
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月08日
    	 */
    	@Override
    	public boolean isAvailable(Connection connection) {
    		try {
    			if (connection == null || connection.isClosed()) {
    				return false;
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return true;
    		
    	}
    
    	/**
    	 * @Description:使用重复利用机制获取连接:如果总连接未超过最大连接,则从空闲连接池获取连接或者创建一个新的连接,如果超过最大连接,则等待一段时间以后,继续获取连接
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月08日
    	 */
    	@Override
    	public synchronized Connection getConnection() {
    		Connection connection = null;
    		//空闲连接和活动连接的总数加起来 小于 最大配置连接
    		System.out.println("当前空闲连接总数:"+freeConnection.size()+" 当前活动连接总数"+activeConnection.size()+", 配置最大连接数:"+ dDbProperties.getMaxConnections());
    		if (freeConnection.size()+activeConnection.size() < dDbProperties.getMaxConnections()) {
    			//空闲连接池,是否还有还有连接,有就取出来,没有就创建一个新的。
    			if (freeConnection.size() > 0) {
    				connection = freeConnection.poll();
    				System.out.println("从空闲线程池取出线程:"+connection+"当前空闲线程总数:"+freeConnection.size());
    			} else {
    				connection = newConnection();
    				System.out.println("空闲连接池没有连接,创建连接"+connection);
    			}
    			//拿到的连接可用,就添加活动连接池,否则就递归继续找下一个
    			boolean available = isAvailable(connection);
    			if (available) {
    				activeConnection.add(connection);
    			} else {
    				connection = getConnection();
    			}
    
    		} else {
    			System.out.println("当前连接数已达到最大连接数,等待"+dDbProperties.getRetryConnectionTimeOut()+"ms以后再试");
    			try {
    				wait(dDbProperties.getRetryConnectionTimeOut());
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			connection = getConnection();
    		}
    		return connection;
    
    	}
    
    	/**
    	 * @Description:使用可回收机制释放连接:如果连接可用,并且空闲连接池没有满,则把连接归还到空闲连接池,否则关闭连接
    	 * @author hutao
    	 * @mail hutao_2017@aliyun.com
    	 * @date 2020年07月09日
    	 */
    	@Override
    	public synchronized void releaseConnection(Connection connection) {
    		try {
    			if (isAvailable(connection) && freeConnection.size() < dDbProperties.getMaxFreeConnections()) {
    				freeConnection.add(connection);
    				System.out.println("空闲线程池未满,归还连接"+connection);
    				
    			} else {
    				connection.close();
    				System.out.println("空闲线程池已满,关闭连接"+connection);
    			}
    			activeConnection.remove(connection);
    			notifyAll();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    3.5演示代码

    创建20个线程,每个线程操作数据库20次,每次操作往数据库写入一条数据。
    创建表结构

    CREATE TABLE `test` (
      `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    
    public class Test001 {
    
    	public static void main(String[] args) {
    			ThreadConnection threadConnection = new ThreadConnection();
    			for (int i = 0; i < 20; i++) {
    				Thread thread = new Thread(threadConnection, "线程:" + i);
    				thread.start();
    			}
    	}
    }
    
    class ThreadConnection implements Runnable {
    
    	public void run() {
    		for (int i = 0; i < 20; i++) {
    			Connection connection = DbPoolManager.getConnection();
    			System.out.println(Thread.currentThread().getName() + ",connection:" + connection);
    			Statement statement;
    			try {
    				statement = connection.createStatement();
    				String selectsql = "select * from test";
    				statement.execute(selectsql);
    				
    				String insertsql = "insert into test(name) VALUES('"+Thread.currentThread().getName()+connection+"')";
    				statement.execute(insertsql);
    				statement.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    			DbPoolManager.releaseConnection(connection);
    		}
    	}
    }
    

    3.6演示效果说明

    如果每个连接都能正常工作,总共20个并发线程,每个线程执行20次数据库查询,插入操作,执行完毕后,数据库应该有400条数据
    在这里插入图片描述
    在这里插入图片描述
    初始化阶段
    在这里插入图片描述
    达到最大连接数,进入重试阶段
    在这里插入图片描述
    连接的获取和归还到空闲池
    在这里插入图片描述
    空闲连接池已满,关闭连接
    在这里插入图片描述
    至此,完毕!

    展开全文
  • 在用kettle进行数据库数据同步时,需要设置数据库连接信息,但是一般开发环境和生产环境数据库不一样,如果在开发阶段把数据库连接信息写死,那么在生产环境部署时又要重新打开.krt或.kjb文件重新编辑数据库连接信息...

    在用kettle进行数据库数据同步时,需要设置数据库连接信息,但是一般开发环境和生产环境数据库不一样,如果在开发阶段把数据库连接信息写死,那么在生产环境部署时又要重新打开.krt或.kjb文件重新编辑数据库连接信息。解决方法是数据库连接信息可以通过命令行参数传入,这样只需要在启动时改变一下参数就可以了。下面以配置一个简单的表输入为例来说明。

    新建一个转换,数据库连接信息设置如下,注意我们都是用的变量,没有写死数据库连接信息。这里说个小插曲,如果我们定义的数据库连接没有在转换中用到,那么下次打开文件的时候这个定义的数据库连接就会消失,不得不吐槽这设计。。。

    接下来我们定义一个转换,随便从数据库查点什么。

    接下来在文件空白处右键,选择“转换设置”,在命名参数标签下设置我们刚才用到的4个参数。这个参数还可以设置默认值,也就是我们在命令行不指定参数值时会用默认值,设置默认值还有个好处是我们在spoon中调试时可以直接用这个默认值,不然每次我们在spoon中运行ktr文件时还要手动输入这些参数。我这里就先不设置了。

    以上都设置好后,保存文件,然后输入如下命令执行即可将参数传入.ktr文件中进行使用。这里为了后期方便修改参数值,我设置了一些bat相关的变量。命令行有一个地方一定要注意,/param:"xxx=xxx"这里的双引号不能省略,我就在这里踩坑了,不加双引号参数是传递不了的。

    :: kettle软件安装路径
    set kettlePath=E:\zzj\apps\data-integration
    :: *.kjb文件存放路径
    set jobPath=E:\zzj\javaweb\ETL
    :: 数据库连接url
    set dbUrl=localhost
    :: 数据库名
    set dbName=mybatis
    :: 数据库连接用户名
    set dbUsername=root
    :: 数据库连接密码
    set dbPassword=123456
    %kettlePath%\pan /file %jobPath%\test.ktr /param:"db_url=%dbUrl%" /param:"db_name=%dbName%" /param:"db_username=%dbUsername%" /param:"db_password=%dbPassword%"

    执行成功

     

     

    展开全文
  • JDBC与数据库连接

    万次阅读 多人点赞 2018-10-24 23:58:23
    JDBC简介,driver类型,JDBC连接,使用技巧; 连接,短连接,长连接连接池; 池化思想; 配置,基本配置,关键配置,性能配置; 连接池工具; druid; HikariCP; flexy-pool;

    JDBC

    简介

    JDBC 是Java应用程序用来连接关系型数据库的标准API,为多种关系型数据库提供一个统一的访问接口。Sun公司一共定义4种 JDBC 驱动类型,一般使用第4种,该类型的Driver完全由Java代码实现,通过使用socket与数据库进行通信。

    1. JDBC-ODBC Bridge driver (bridge driver),JDBC-ODBC桥驱动程序;
    2. Native-API/partly Java driver (native driver),JDBC本地API;
    3. All Java/Net-protocol driver (middleware driver),JDBC-Net纯Java;
    4. All Java/Native-protocol driver (Pure java driver),100%纯Java。

    常规数据库连接一般由以下六个步骤构成:

    • 装载数据库驱动程序;
    • 建立数据库连接;
    • 创建数据库操作对象;
    • 访问数据库,执行sql语句;
    • 处理返回结果集;
    • 断开数据库连接。

    此处省略常规 JDBC 获取连接、执行SQL、获取结果集代码,一般严格遵守上面的流程,网上一大堆;

    连接角度看 JDBC

    在这里插入图片描述
    上图大致画出以访问MySQL为例,执行一条 SQL 命令,不使用连接池的情况下,需要经过哪些流程。

    1. TCP建立连接的三次握手;
    2. MySQL认证的三次握手;
    3. 真正的SQL执行;
    4. MySQL的关闭;
    5. TCP的四次握手关闭;

    为了执行一条SQL,有很多网络交互。
    优点:实现简单。
    缺点:

    1. 网络IO较多;
    2. 数据库的负载较高;
    3. 响应时间较长及QPS较低;
    4. 应用频繁的创建连接和关闭连接,导致临时对象较多,GC频繁;
    5. 在关闭连接后,会出现大量TIME_WAIT 的TCP状态(在2个MSL之后关闭)。

    JDBC技巧

    1. 使用PrearedStatement,可以通过预编译的方式避免在拼接SQL时造成SQL注入。
    2. 使用ConnectionPool
    3. 禁用自动提交
      这个最佳实践在我们使用JDBC的批量提交的时候显得非常有用,将自动提交禁用后,你可以将一组数据库操作放在一个事务中,而自动提交模式每次执行SQL语句都将执行自己的事务,并且在执行结束提交。
    4. 使用Batch Update:批量更新/删除,比单个更新/删除,能显著减少数据传输的往返次数,提高性能。
    5. 使用列名获取ResultSet中的数据,从而避免invalidColumIndexError
      JDBC中的查询结果封装在ResultSet中,我们可以通过列名和列序号两种方式获取查询的数据,当我们传入的列序号不正确的时候,就会抛出invalidColumIndexException,例如你传入了0,就会出错,因为ResultSet中的列序号是从1开始的。另外,如果你更改了数据表中列的顺序,你也不必更改JDBC代码,保持了程序的健壮性。有一些Java程序员可能会说通过序号访问列要比列名访问快一些,确实是这样,但是为了程序的健壮性、可读性,我还是更推荐你使用列名来访问。
    6. 使用变量绑定而不是字符串拼接
      使用PreparedStatment可以防止注入,而使用?或者其他占位符也会提升性能,因为这样数据库就可以使用不同的参数执行相同的查询,提示性能,也防止SQL注入。
    7. 关闭Connection 等资源,确保资源被释放;
    8. 选择合适的JDBC驱动,参考前文,选择第四种;
    9. 尽量使用标准的SQL语句,从而在某种程度上避免数据库对SQL支持的差异
      不同的数据库厂商的数据库产品支持的SQL的语法会有一定的出入,为了方便移植,推荐使用标准的ANSI SQL标准写SQL语句。
    10. 使用正确的getXXX()方法
      当从ResultSet中读取数据的时候,虽然JDBC允许你使用getString()和getObject()方法获取任何数据类型,推荐使用正确的getter方法,这样可以避免数据类型转换。

    连接池

    先看看连接的简介。

    连接

    当数据库服务器和客户端位于不同的主机时,就需要建立网络连接来进行通信。客户端必须使用数据库连接来发送命令和接收应答、数据。通过提供给客户端数据库的驱动指定连接字符串后,客户端就可以和数据库建立连接。查阅程序语言手册来获知通过何种方式使用短连接、长连接。

    1. 短连接
      短连接是指程序和数据库通信时需要建立连接,执行操作后,连接关闭。短连接简单来说就是每一次操作数据库,都要打开和关闭数据库连接,基本步骤是:连接 -> 数据传输 -> 关闭连接

    在慢速网络下使用短连接,连接的开销会很大;在生产繁忙的系统中,连接也可能会受到系统端口数的限制,如果要每秒建立几千个连接,那么连接断开后,端口不会被马上回收利用,必须经历一个FIN阶段等待,直到可被回收利用为止,这样就可能会导致端口资源不够用。在Linux上,可以通过调整/proc/sys/net/ipv4/ip_local_port_range来扩大端口的使用范围;调整/proc/sys/net/ipv4/tcp_fin_timeout来减少回收延期(如果想在应用服务器上调整这个参数,一定要慎重!)。
    另外一个办法是主机使用多个IP地址。端口数的限制其实是基于同一个IP:PORT的,如果主机增加IP,MySQL就可以监听多个IP地址,客户端也可以选择连接某个IP:PORT,这样就增加端口资源。

    1. 长连接
      长连接是指程序之间的连接在建立之后,就一直打开,被后续程序重用。使用长连接的初衷是减少连接的开销。当收到一个永久连接的请求时,检查是否已经存在一个相同的永久连接。存在则复用;不存在则重新建立一个新的连接。所谓相同的连接是指基本连接信息,即用户名、密码、主机及端口都相同。

    从客户端的角度来说,使用长连接有一个好处,可以不用每次创建新连接,若客户端对MySQL服务器的连接请求很频繁,永久连接将更加高效。对于高并发业务,如果可能会碰到连接的冲击,推荐使用长连接或连接池。

    从服务器的角度来看,它可以节省创建连接的开销,但维持连接也是需要内存的。如果滥用长连接的话,可能会使用过多的MySQL服务器连接。现代的操作系统可以拥有几千个MySQL连接,但很有可能绝大部分都是睡眠状态的,这样的工作方式不够高效,而且连接占据内存,也会导致内存的浪费。

    对于扩展性好的站点来说,其实大部分的访问并不需要连接数据库。如果用户需要频繁访问数据库,那么可能会在流量增大的时候产生性能问题,此时长短连接都是无法解决问题的,所以应该进行合理的设计和优化来避免性能问题。

    如果客户端和MySQL数据库之间有连接池或Proxy代理,一般在客户端推荐使用短连接。对于长连接的使用一定要慎重,不可滥用。如果没有每秒几百、上千的新连接请求,就不一定需要长连接,也无法从长连接中得到太多好处。在Java语言中,由于有连接池,如果控制得当,则不会对数据库有较大的冲击,但PHP的长连接可能导致数据库的连接数超过限制,或者占用过多的内存。

    1. 连接池
      数据库连接池是一些网络代理服务或应用服务器实现的特性,实现一个持久连接的“池”,允许其他程序、客户端来连接,这个连接池将被所有连接的客户端共享使用,连接池可以加速连接,也可以减少数据库连接,降低数据库服务器的负载。

    2. 持久连接和连接池的区别
      长连接是一些驱动、驱动框架、ORM工具的特性,由驱动来保持连接句柄的打开,以便后续的数据库操作可以重用连接,从而减少数据库的连接开销。而连接池是应用服务器的组件,它可以通过参数来配置连接数、连接检测、连接的生命周期等。

    如果连接池或长连接使用的连接数很多,有可能会超过数据库实例的限制,那么就需要留意连接相关的设置,比如连接池的最小、最大连接数设置,以及php-fpm的进程个数等,否则程序将不能申请新的连接。

    最小连接数和最大连接数的设置要考虑到以下几个因素:
    最小连接数:连接池一直保持的数据库连接,如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费;
    最大连接数:连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作;
    如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过这些大于最小连接数的数据库连接在使用完不会马上被释放,将被放到连接池中等待重复使用或是空间超时后被释放。

    池化

    连接池类似于线程池或者对象池,数据库连接池为系统的运行带来以下优势:

    • 昂贵的数据库连接资源得到重用;
    • 减少数据库连接建立和释放的时间开销,提高系统响应速度;
    • 统一的数据库连接管理,避免连接资源的泄露。

    连接池负责:连接建立、连接释放、连接管理、连接分配。

    数据库连接池运行机制:
    系统初始化时创建连接池,程序操作数据库时从连接池中获取空闲连接,程序使用完毕将连接归还到连接池中,系统退出时,断开所有数据库连接并释放内存资源。

    数据库连接池生命周期
    数据库每个读写操作需要一个连接。数据库连接调用流如下图:
    在这里插入图片描述
    调用流程为:

    • 应用数据层向DataSource请求数据库连接
    • DataSource使用数据库Driver打开数据库连接
    • 创建数据库连接,打开TCP socket
    • 应用读/写数据库
    • 如果该连接不再需要就关闭连接
    • 关闭socket

    为什么连接池快很多?
    分析池连接管理的调用流程:
    在这里插入图片描述
    无论何时请求一个连接,池数据源会从可用的连接池获取新连接。仅当没有可用的连接而且未达到最大的连接数时连接池将创建新的连接。close()方法把连接返回到连接池而不是真正地关闭它。
    在这里插入图片描述
    重用数据库连接最明显的原因:

    • 减少应用程序和数据库管理系统创建/销毁TCP连接的OS I/O开销
    • 减少JVM对象垃圾
    • 缓冲安全:连接池是即将到来的连接请求的有界缓冲区。如果出现瞬间流量尖峰,连接池会平缓这一变化,而不是使所有可用数据库资源趋于饱和。
    • 等待步骤和超时机制,可有效防止数据库服务器过载。如果一个应用消耗太多数据库流量,为防止它将数据库服务器压垮,连接池将减少它对数据库的使用。

    配置

    连接池配置大体可以分为基本配置、关键配置、性能配置等主要配置。

    基本配置

    基本配置是指连接池进行数据库连接的四个基本必需配置:传递给JDBC驱动的用于连接数据库的用户名、密码、URL以及驱动类名。
    在Druid连接池的配置中,driverClassName可配可不配,如果不配置会根据url自动识别dbType(数据库类型),然后选择相应的driverClassName。

    关键配置

    为了发挥数据库连接池的作用,在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
    最小连接数:是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库资源被浪费。
    初始化连接数:连接池启动时创建的初始化数据库连接数量。
    最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队列中。
    最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负数使得无限等待(根据不同连接池配置)。

    数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过maxWait,则会报错;如果当前正在使用的连接数没有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。

    性能配置

    预缓存设置:PSCache,对支持游标的数据库性能提升巨大,比如说oracle。JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池,所以设置这个参数需要考虑到多方面的因素。
    单个连接拥有的最大缓存数:要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100

    连接有效性检测设置:连接池内部有机制判断,如果当前的总的连接数少于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前连接池中某个连接在空闲timeBetweenEvictionRunsMillis时间后任然没有使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制(mysql连接在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的情况,这时候设置一个testWhileIdle参数为true,可以保证连接池内部定时检测连接的可用性,不可用的连接会被抛弃或者重建,最大情况的保证从连接池中得到的Connection对象是可用的。当然,为了保证绝对的可用性,你也可以使用testOnBorrow为true(即在获取Connection对象时检测其可用性),不过这样会影响性能。

    超时连接关闭设置:removeAbandoned参数,用来检测当前使用的连接是否发生连接泄露,所以在代码内部就假定如果建立连接的时间很长,则将其认定为泄露,继而强制将其关闭掉。

    工具

    • C3P0:开源JDBC连接池,实现数据源和JNDI绑定,包括实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。单线程,性能较差,适用于小型系统,代码600KB左右。
    • BoneCP:开源的快速的 JDBC 连接池。只有四十几K(运行时需要log4j和Google Collections的支持)。另外个人觉得 BoneCP 有个缺点是,JDBC驱动的加载是在连接池之外的,这样在一些应用服务器的配置上就不够灵活。官方说法BoneCP是一个高效、免费、开源的Java数据库连接池实现库。设计初衷就是为了提高数据库连接池性能,完美集成到一些持久化产品如Hibernate和DataNucleus中。特色:高度可扩展,快速;连接状态切换的回调机制;允许直接访问连接;自动化重置能力;JMX支持;懒加载能力;支持XML和属性文件配置方式;较好的Java代码组织。
    • DBCP:Database Connection Pool,一个依赖Jakarta commons-pool对象池机制的数据库连接池,单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar,预先将数据库连接放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完再放回。单线程,并发量低,性能不好,适用于小型系统。
    • Tomcat Jdbc Pool:Tomcat在7.0以前都是使用common-dbcp做为连接池组件,但是dbcp是单线程,为保证线程安全会锁整个连接池,性能较差,dbcp有超过60个类,也相对复杂。Tomcat从7.0开始引入新增连接池模块叫做Tomcat jdbc pool,基于Tomcat JULI,使用Tomcat日志框架,完全兼容dbcp,通过异步方式获取连接,支持高并发应用环境,超简单,核心文件只有8个,支持JMX,支持XA Connection。
    • Druid:下面详细讲解;
    • HikariCP:下面详细讲解;

    本文不会详细介绍前面几种连接池工具,基本上过时;

    Druid

    简介

    阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。支持所有JDBC兼容的数据库。Druid针对Oracle和MySQL特别优化,比如Oracle的PS Cache内存占用优化,MySQL的ping检测优化。Druid提供SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。Druid能够提供强大的监控和扩展功能,是一个可用于大数据实时查询和分析的高容错、高性能的开源分布式系统,尤其是当发生代码部署、机器故障以及其他产品系统遇到宕机等情况时,Druid仍能够保持100%正常运行。主要特色:为分析监控设计;快速的交互式查询;高可用;可扩展;
    简单SQL语句用时10微秒以内,复杂SQL用时30微秒。
    通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。

    • Proxool:一个Java SQL Driver驱动程序,完全可配置。

    todo

    spring boot with druid

    以目前也是以后的 Java EE 发展方向的spring boot 为例,说明如何集成druid。其他传统 SSH & SSM应用架构大致类似,但是配置会复杂一些;

    HikariCP

    简介

    新一代数据库连接池,性能相当优异,spring boot 2 默认使用的 dbcp 从之前的 tomcat-pool 换成HikariCP 。
    在 druid 以及 HikariCP 出现之前,BoneCP 可以说是性能最好的 dbcp 之一,https://jolbox.com/index.html?page=https://jolbox.com/benchmarks.html
    官网:http://www.jolbox.com/

    可是现在,BoneCP 的GitHub 的截图。
    在这里插入图片描述
    GitHub

    优势

    Springboot 2.0 默认使用的连接池换成HikariCP,因为其性能格外优异。而其性能来源于HikariCP的在以下几个方面的优化:

    1. 字节码精简 :优化代码,直到编译后的字节码最少,这样CPU缓存可以加载更多的程序代码;
    2. 优化代理和拦截器:减少代码,例如HikariCP的Statement proxy只有100行代码,只有BoneCP的十分之一;
    3. 自定义数组类型(FastStatementList)代替ArrayList:避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描;
    4. 自定义集合类型,使用ConcurrentBag提高并发读写的效率;
    5. 其他针对BoneCP缺陷的优化,比如对于耗时超过一个CPU时间片的方法调用的研究。

    JDBC连接池的实现,主要是对JDBC中几个核心对象Connection、Statement、PreparedStatement、CallableStatement以及ResultSet的封装与动态代理。

    参考:GitHub-HikariCP-wiki

    常用配置项

    • dataSourceClassName
      接收字符串值,默认为空。JDBC driver 提供的 DataSource 类名。不同的 JDBC driver 会有其相对应的类名(不支持 XA data sources)。如果使用了 jdbcUrl 配置项则不需要配置此项。
    • jdbcUrl
      接收字符串值,默认为空。此属性将使 HikariCP 使用“基于驱动管理器”(DriverManager-based)的配置。由于多种原因,我们认为基于数据源(DataSource-based)的配置是更好的选择。但对许多部署实例来讲却也区别不大。当使用此属性来配置“旧”的 JDBC 驱动时,你可能也需要设置 driverClassName 属性,但可以试一试不设置是否能行得通。
    • username / password
      接收字符串值,默认为空。对 DataSource 来讲,username和password仅会在调用 DataSource.getConnection(username, password) 时用到。但在使用基于驱动(Driver-based)配置时,HikariCP 会使用 username 的值去设置调用 DriverManager.getConnection(jdbcUrl, props) 方法时传入的 Properties 中的 user 属性。如果并不是你想要的,你需要避免执行这个方法。
    • autoCommit
      布尔值,默认为 true。控制从连接池中返回的连接的 auto-commit 行为。通常情况下会设置为 false。比如使用Spring 统一管理数据库事务,这时就需要禁用 auot-commit。
    • connectionTimeout
      接收数值,默认为30000(30秒),最小可接收值为250ms。设置客户端获取连接前等待的最大毫秒数,即超时时间。如果超过了这个时间后仍然没有可用的数据库连接返回,SqlException 则会被抛出。
    • idleTimeout
      接收数值,默认为600000(10分),最小可接收值为10000(10秒)。此属性控制一个连接保持空闲状态的最大超时时间。只有当 minimumIdle 小于 maximumPoolSize 时此属性才会生效。一个数据库连接是否退化为空闲状态需要平均15秒+,最多30秒+。设置0表示空闲的连接永远不会从连接池中销毁。
    • maxLifetime
      接收数值,默认为1800000(30分)。此属性为单个连接在连接池中的最长生命周期时间。连接只有在被关闭后才会被移除。强烈建议设置此属性,并且至少应该比任何数据库或组件强制要求的连接时间少30秒。此属性设置为0表示没有最长生命周期时间。
    • connectionTestQuery
      接收字符串值,默认为空。如果数据库驱动支持 JDBC4,则强烈建议不要设置此属性。此属性是为那些不支持 JDBC4 Connection.isValid() API 的老旧数据库准备的。这条查询语句会在连接从连接池返回给客户端之前执行,用以验证返回的数据库连接仍然可用。再次重申,在不设置此属性时尝试启动数据库连接池,如果你的数据库驱动不支持 JDBC4,HikariCP 会记录下错误信息。
      在 c3p0 中,这个属性的名称是 preferredTestQuery;在 tmocat-jdbc 中,这个属性的名称叫做 validationQuery。属性值一般设置为 “Select 1”。
    • minimumIdle
      接收数值,默认和 maximumPoolSize 相同。设置 HikariCP 在连接池中保存的最少空闲连接数。如果空闲连接数少于此属性值,HikariCP 会尽力快速高效的增加连接。不过,为了最高性能和峰值弹性需求,我们建议不要设置此属性,而是让 HikariCP 作为一个固定大小的连接池。
    • maximumPoolSize
      接收数值,默认为10。设置 HikariCP 在连接池中保存的最多连接数,包括空闲的和正在使用的连接。此属性的合理值应该由程序的运行环境决定。当连接池中没有空闲连接,调用 getConnection() 会一直阻塞直到超过 connectionTimeout 设置的超时时间。
    • poolName
      接收字符串值,默认值为自动生成。此属性为连接池设置用户自定义的名称,并会在日志中显示。设置连接池名称主要是为了配合 JMX 在控制台日志中区分不同的连接池和连接池配置。注意,通过我们实践发现,如果需要配合使用 JMX,最好设置自定义的连接池名称。使用默认的自动生成的连接池名称有可能会出现意想不到的问题。
    • prepStmtCacheSize
      接收数值,默认为25。此属性设置 MySQL 驱动在每个连接会缓存的 Prepared Statement 数量。推荐设为250到500之间。
    • prepStmtCacheSqlLimit
      接收数值。此属性为 MySQL 驱动缓存的 Prepared SQL statement 的最大长度。MySQL 默认为256。此默认值远远小于生成的语句长度,推荐将其设置为2048。
    • cachePrepStmts
      布尔值,默认为 false。打开预处理语句缓存。如果为 false,prepStmtCacheSize 和 prepStmtCacheSqlLimit 都不会起作用。
    • useServerPrepStmts
      布尔值。新版的 MySQL 支持服务端预处理语句,这可以极大的提高性能。新版MySQL建议设置为 true。

    spring boot with HikariCP

    initialSize:默认值是 0,连接池创建连接的初始连接数目。
    minIdle : 默认是 0,连接数中最小空闲连接数。
    maxIdle : 默认是 8,连接池中最大空闲连接数。
    maxActive : 默认值是 8, 连接池中同时可以分派的最大活跃连接数。
    maxWait : 默认值是无限大,当连接池中连接已经用完,等待建立一个新连接的最大毫秒数 ( 在抛异常之前 )。
    validationQuery : 一条 sql 语句,用来验证数据库连接是否正常。这条语句必须是一个查询模式,并至少返回一条数据。一般用“ select 1 ”。
    minEvictableIdleTimeMilis : 默认值是 1000 * 60 * 30(30 分钟 ) 单位毫秒,连接池中连接可空闲的时间。
    timeBetweenEvictionRunsMilis : 默认值是 -1 ,每隔一段多少毫秒跑一次回收空闲线程的线程。
    对于minEvictableIdleTimeMilis、timeBetweenEvictionRunsMilis这两个参数,timeBetweenEvictionRunsMilis必须大于1且小于minEvictableIdleTimeMilis,建议是minEvictableIdleTimeMilis的五分之一或十分之一。

    HikariCP v.s. Druid

    不具有可比性,HikariCP 追求性能,Druid 偏向监控;druid 默认开启公平锁导致性能下降,有阿里生产环境大数据验证。
    参考:issue

    其他工具

    flexy-pool

    GitHub
    GitHub-wiki
    tutorials

    FlexyPool adds metrics and fail-over strategies to a given Connection Pool, allowing it to resize on demand.
    大意:增加监控,容错,和自适应调整参数功能。

    从其GitHub源码组织结构,即可得知,根据不同的连接池工具,引用不同的依赖。

    优化

    数据库连接池本质上是一种缓存,它是一种抗高并发的手段。数据库连接池优化主要是对参数进行优化,DBCP连接池的具体参数如下(其他各种连接池的配置参数大同小异,需要区别对待):

    • initialSize:初始连接数,第一次getConnection的,而不是应用启动时。初始值可以设置为并发量的历史平均值;
    • minIdle:最小保留的空闲连接数。DBCP会在后台开启一个回收空闲连接的线程,当该线程进行空闲连接回收的时候,会保留minIdle个连接数。一般设置为5,并发量实在很小可以设置为1.
    • maxIdle:最大保留的空闲连接数,按照业务并发高峰设置。比如并发高峰为20,那么当高峰过去后,这些连接不会马上被回收,如果过一小段时间又来一个高峰,那么连接池就可以复用这些空闲连接而不需要频繁创建和关闭连接。
    • maxActive:最大活跃连接数,按照可以接受的并发极值设置。比如单机并发量可接受的极值是100,那么这个maxActive设置成100后,就只能同时为100个请求服务,多余的请求会在最大等待时间之后被抛弃。这个值必须设置,可以防止恶意的并发攻击,保护数据库。
    • maxWait:获取连接的最大等待时间,建议设置的短一点,比如3s,这样可以让请求快速失败,因为一个请求在等待获取连接的时候,线程是不可以被释放的,而单机的线程并发量是有限的,如果这个时间设置的过长,比如网上建议的60s,那么这个线程在这60s内是无法被释放的,只要这种请求一多,应用的可用线程就少了,服务就变得不可用了。
    • minEvictableIdleTimeMillis:连接保持空闲而不被回收的时间,默认30分钟。
    • validationQuery:检测连接是否有效的sql语句,建议设置;
    • testOnBorrow:申请连接的时候对连接进行检测,不建议开启,严重影响性能;
    • testOnReturn:归还连接的时候对连接进行检测,不建议开启,严重影响性能;
    • testWhileIdle:开启以后,后台清理连接的线程会没隔一段时间对空闲连接进行validateObject,如果连接失效则会进行清除,不影响性能,建议开启;
    • numTestsPerEvictionRun:代表每次检查链接的数量,建议设置和maxActive一样大,这样每次可以有效检查所有的链接;
    • 预热连接池:对于连接池,建议在启动应用的时候进行预热,在还未对外提供访问之前进行简单的sql查询,让连接池充满必要的连接数。

    参考:
    JDBC驱动程序类型
    MySQL之长连接、短连接、连接池
    the-anatomy-of-connection-pooling
    数据库连接池极简教程
    高性能数据库连接池的内幕
    五大理由分析Springboot 2.0为什么选择HikariCP

    展开全文
  • 前段时间在一个老项目中经历过一个问题:一个 Dubbo 服务,启动的时候慢的要死,后来看日志查原因整个过程一直在初始化数据库连接。一看数据库连接参数,连接池大小:1024。 很多入行晚的同学没有经历过手写 JDBC ...
  • 本篇内容综合广大网友提供内容,笔者经过整理,对数据库连接池原理和实现过程做个很系统的并且通俗易懂的分析讲解,以及手写一个连接池实现过程作为演示。 一、早期通过JDBC方式操作数据库 我们先来看早期使用JDBC...
  • 通过Java程序测试数据库连接信息

    千次阅读 2016-10-28 11:45:48
    很就没Java了,今天简单问了下行情,如今都是Java 9的时代了,老系统基本上都是在Java 7。 Oracle中很早就糅合了Java,Oracle 10g中自带Java 4,Oracle 11g中是Java 5,到了12c还是得与时俱进,是Java 6。当然相比...
  • 两款免费、好用的数据库连接工具

    千次阅读 2021-08-06 12:25:32
    Navicat 是以直觉化的图形用户界面而建的,让你可以以安全并且简单的方式创建、组织、访问并共用信息。 1、安装步骤 (1)解压navicat_premium12文件,得到安装文件和破解文件。 (2)双击navicat12024_...
  • 数据库连接池原理详解与自定义连接池实现

    万次阅读 多人点赞 2017-05-17 18:18:54
    实现原理数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数制约。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的...
  • 几种常用数据库连接池的使用

    万次阅读 多人点赞 2019-02-14 12:38:38
    一、应用程序直接获取数据库连接的缺点  用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的...
  • Mybatis深入之获取数据库连接

    万次阅读 多人点赞 2015-06-22 22:55:56
    Mybatis深入之获取数据库连接简介主要记录Mybatis何时获取数据库连接以及获取数据库连接的过程。难点在于明白在使用Mybatis数据库连接池情况下的数据库连接的获取过程。
  • 如果我们把数据库连接信息也就是数据库连接字符串在web.config里,不但加强了程序的安全,同时也极大的方便了程序的修改。 在web.config文件里添加关键字key是通过标记来实现的,但是appSettings标记通常放在.......
  • SpringBoot 配置数据库连接的方法

    千次阅读 2019-11-12 17:05:22
    SpringBoot 配置数据库连接的方法 前言 经过spring,我们知道,要配置数据库的连接还是很繁琐的,现在有了springboot,一切都变得简单起来 1、将数据库信息写进application.properties文件中 jdbc.url = jdbc:mysql:...
  • Java连接MySQL数据库步骤

    万次阅读 多人点赞 2019-08-31 17:10:47
    Java连接MySQL数据库步骤 声明,只推荐你看代码学会我的步骤,逻辑,还有用的所有方法 第一, ​ 安装mysql数据库配置(https://www.jianshu.com/p/ea4accd7afb4),安装还有配置教程,按照步骤来肯定没错,里面是...
  • 数据库连接技术整理

    万次阅读 2017-02-09 15:40:14
    ODBC(Open Database Connectivity,开放数据库互连)是微软公司开放服务结构(WOSA,Windows Open Services Architecture)中有关数据库的一个组成部分,它建立了一组规范,并提供了一组对数据库访问的标准API...
  • 数据库连接池DataSource

    千次阅读 2017-09-17 18:40:28
    一:数据库连接池介绍 什么是数据库连接数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的...
  • 谈谈数据库连接池的原理

    万次阅读 多人点赞 2013-11-06 10:14:07
    这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包。
  • 同样,可以将数据库连接字符串等一些核心信息,藏在这个文件里面。 具体做法如下,对没有任何属性的connectionStrings字段进行属性的赋予: 譬如改写成如下之后,自定义此配置字符串为myCon之后, 在任意...
  • 这是我的一个应用MVC模式编写的javaWeb程序,里面有完整的项目及嫁包,直接导入项目即可运行,代码结构清晰,是新手学习JAVAWEB的完美示例
  • Eclipse连接Mysql数据库学生信息管理系统
  • JavaWeb——教你db数据库连接

    千次阅读 2017-12-31 12:56:51
    db连接类 ...创造一个数据库连接对象(Connection对象,代表与数据源进行的唯一会话。)。 创建编译语句对象(Statement对象,建立了到特定数据库的连接之后,就可用该连接发送 SQL 语句。)。 创建预编
  • 两个参数间的关系:sessions=1.1*processes+5目前总结的语句,在查看数据的连接情况很有用,完程序一边测试代码一边查看数据库连接的释放情况有助于分析优化出一个健壮的系统程序来。1.Sql代码1.select count(*) ...
  • JDBC是Java数据连接技术(Java Database Connection)的简称,提供连接各种常用数据库的能力。 •JDBC驱动由数据库厂商提供 –在个人开发与测试中,可以使用JDBC-ODBC桥连方式 –在生产型开发中,推荐使用纯Java...
  • 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。 为什么要使用连接池  数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用...
  • 数据库连接池优缺点详解

    千次阅读 2017-02-27 08:28:42
    二、Java连接数据库方法概述  java.sql提供了一些接口和类,用于支持数据库增删改查等相关的操作。该jar包定义了java访问各种不同数据库(mysql,oracle,sqlserver。。。。。)的统一接口和标准。同时,各个...
  • Springboot+druid数据库连接池使用

    万次阅读 多人点赞 2018-06-08 17:23:10
    1. 为什么要使用数据库连接池 使用数据库连接池主要考虑到程序与数据库建立连接的性能。创建一个新的数据库是一个很耗时的过程,在使用完之后,可能还需要不断的释放建立的连接,对资源的损耗大。 而采用数据库...
  • C3P0 与 DBCP 数据库连接池使用和比较

    千次阅读 2019-02-05 22:03:59
    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主威威喵原创,请多支持与指教。 ... 我们知道JDBC是连接数据库的基石,...通常我们使用JDBC获取数据库连接时,只需要配置几步必要的参数就...
  • 3.操作C#方法下的连接语句: 连接前导入引用:MySql.Data.dll (顶部有下载链接),不知道怎么导入,可以去我的另一篇博客 在顶部using一下:using MySql.Data.MySqlClient; 代码如下: using System; usin...
  • JDBC之获取数据库连接方法详解

    万次阅读 多人点赞 2021-03-14 15:46:58
    JDBC接口(API)包括两个层次:面向应用的API:面向数据库的API:注意:JDBC程序编写步骤:CRUD编程(返回结果集的情况(也就是查))(不返回结果集的情况(也就是增删改))补充:获取数据库连接:要素一:...
  • spring: datasource: url: jdbc:mysql://localhost:3306/boot_crm?serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 693,622
精华内容 277,448
关键字:

数据库连接信息怎么写