一、JDBC驱动
JDBC驱动的加载:
1、通过容器加载:
对于有容器的Java应用,可以直接将相应的驱动jar包放在容器的lib目录下,例如在Tomcat做容器的web应用,将驱动复制到tomcat的lib子目录下;
2、应用运行时加载:
如果希望应用自行加载相应的驱动,需要maven为应用打jar/war包时指定好搜寻驱动jar时的classpath,请参考:
https://maven.apache.org/shared/maven-archiver/examples/classpath.html
https://www.cnblogs.com/snaildev/p/8341610.html
示例一(可执行jar包下有lib目录存放依赖jar包):
<build> <finalName>image</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>some.package.MainClass</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build>
业务自行加载JDBC驱动时,需要在应用用JDBC之前执行如下操作加载驱动:
Class.forName("com.mysql.jdbc.Driver"); // Then the following begin to use jdbc
二、通过连接池(DataSource的一种)管理与数据库的连接
目前常用的连接池为Druid或Hikari,分别说明如下:
1、Druid连接池:
maven依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.11</version> </dependency>
示例代码:
DruidDataSource createSource(String name, String jdbcUrl, String userName, String password, maxActive, minIdle, maxWait, scanInterval, minActiveTime) { DruidDataSource src = DruidDataSource(); src.setName(name); src.setUrl(jdbcUrl); src.setUsername(userName); src.setPassword(password); src.setDriverClassName(); src.setInitialSize(minIdle); src.setMaxActive(maxActive); src.setMinIdle(minIdle); src.setMaxWait(maxWait); src.setTimeBetweenEvictionRunsMillis(scanInterval); src.setMinEvictableIdleTimeMillis(minActiveTime); src.setTestWhileIdle(); src.setTestOnBorrow(); src.setTestOnReturn(); src.setPoolPreparedStatements(); src.setMaxPoolPreparedStatementPerConnectionSize(); src.setValidationQuery(); src.setRemoveAbandoned(); src.setRemoveAbandonedTimeout(); src.setKeepAlive(); if(!isDataSourceOk(src)){ LOGGER.error("Data source "+ name + "test failed"); } return src; } private static boolean isDataSourceOk(DataSource source){ try (Connection connection = source.getConnection(); PreparedStatement stmt = connection.prepareStatement("select 1"); ResultSet resultSet = stmt.executeQuery()){ resultSet.next(); return true; }catch (Throwable e){ return false; } }
2、Hikari连接池
maven依赖:
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>3.2.0</version> </dependency>
示例代码:
HikariDataSource createSource(String name, String jdbcUrl, String userName, String password, connectionTimeout, idleTimeout, maxLifeTime, poolSize) { HikariDataSource src = HikariDataSource(); src.setPoolName(name); src.setJdbcUrl(jdbcUrl); src.setUsername(userName); src.setPassword(password); src.setDriverClassName(); src.setConnectionTimeout(connectionTimeout); src.setIdleTimeout(idleTimeout); src.setMaxLifetime(maxLifeTime); src.setMaximumPoolSize(poolSize); if(!isDataSourceOk(src)){ LOGGER.error("Data source "+ name + "test failed"); } return src; }
三、处理连接
1、首先通过连接池获取连接,例如:
try(Connection getConnection() SQLException { assert DataSourceManager.getDataSource() != null; return DataSourceManager.getDataSource().getConnection(); }
2、连接的SQL请求提交方式
从连接池(无轮DruidDataSource还是HirakiDataSource)申请到Connection对象拿到后,默认的提交方式为自动提交,即此时调用connection.getAutoCommit()返回的一定是true;
Connection对象归还连接池后,下次再从连接池申请一个Connection,默认的提交方式还是自动提交。需要清楚什时候用自动提交、什么时候适合手工提交。
概况起来就是,看申请到Connection对象到归还Connection对象这期间使用同一个Connection对象做了什么操作:
(1)只有读操作,没有任何写操作:用自动提交;
(2)只有一次对单个表的单条记录有进行写操作:用自动提交;
自动提交的代码示例如下
try(Connection connection = ()) { block.apply(connection); // Do all query or only one update for only one record }
(3)对同一张表的多条记录进行了写操作,或者对不同表的记录分别进行了写操作:根据是否需要回滚、性能要求,确定是否需要支持事务性;如果要支持事物性,必须采用手动提交;
手动提交的操作示例:
try(Connection connection = ()) { boolean success = false; try{ T t = block.apply(connection); // Use this connection process one transaction doCommit(connection); success = true; return t; }finally{ if(!success) { doRollback(connection); // If possible, support rollback when failed } } } 上述复杂过程的block中可能对connection的提交模式进行了修改,为了保持代码的兼容性,上述doCommit()及doRollback()的设计如下: public static void doCommit(Connection connection) throws SQLException { if (!connection.getAutoCommit()) { connection.commit(); } } private static void doRollback(Connection connection) throws SQLException { if (SUPPORT_ROLLBACK && !connection.getAutoCommit()) { connection.rollback(); } }
(4)耗时的操作,数据量比较大,这时依赖数据库的事物性及回滚已经没法达到;这种情况下应该分多次提交,并有应用层提供回滚;
示例如下:
try(Connection connection = ()) { boolean success = false; try{ block1.accept(connection); doCommit(connection); block2.accept(connection); doCommit(connection); success = true; }finally{ if(!success) { block2.clear(connection); block1.clear(connection); } } }
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。