您好,登錄后才能下訂單哦!
一、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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。