java程序與數據創建鏈接,首先要從jdbc提及,而後直接上阿里認爲宇宙最好的數據庫鏈接池druid,而後再說上層程序對象與數據源映射關聯關係的orm-mybatis。java
JDBC(Java DataBase Connectivity)是Java和數據庫(關係型數據庫)之間的一個橋樑。mysql
執行sql過程爲:類加載-->獲取鏈接-->書寫SQL-->執行語句--->處理結果集。git
爲何會有鏈接池的存在?github
由於創建數據庫鏈接是一個很是耗時、耗資源的行爲,因此經過鏈接池預先同數據庫創建一些鏈接,放在內存中,應用程序須要創建數據庫鏈接時直接到鏈接池中申請一個就行,用完後再放回去,極大的提升了數據庫鏈接的性能問題,節省了資源和時間。web
什麼是數據源spring
JDBC2.0 提供了javax.sql.DataSource接口,它負責創建與數據庫的鏈接,當在應用程序中訪問數據庫時 沒必要編寫鏈接數據庫的代碼,直接引用DataSource獲取數據庫的鏈接對象便可。用於獲取操做數據Connection對象。sql
數據源與數據庫鏈接池組件數據庫
數據源創建多個數據庫鏈接,這些數據庫鏈接會保存在數據庫鏈接池中,當須要訪問數據庫時,只須要從數據庫鏈接池中api
獲取空閒的數據庫鏈接,當程序訪問數據庫結束時,數據庫鏈接會放回數據庫鏈接池中。緩存
經常使用的數據庫鏈接池技術:
這些鏈接技術都是在jdbc的規範之上創建完成的。有以下:
C3P0、DBCP、Proxool和DruidX
官方網站文檔:https://github.com/alibaba/druid/wiki/Druid%E8%BF%9E%E6%8E%A5%E6%B1%A0%E4%BB%8B%E7%BB%8D
Druid鏈接池是阿里巴巴開源的數據庫鏈接池項目。Druid鏈接池爲監控而生,內置強大的監控功能,監控特性不影響性能。功能強大,能防SQL注入,內置Loging能診斷Hack應用行爲。
Druid不只僅是一個數據庫鏈接池,它還包含一個ProxyDriver,一系列內置的JDBC組件庫,一個SQL Parser。 支持全部JDBC兼容的數據庫,包括Oracle、MySQL、Derby、Postgresql、SQL Server、H2等等。
Druid針對oracle和mysql作了特別優化,好比Oracle的PS Cache內存佔用優化,MySql的ping檢測優化。Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,這是一個手寫的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象語法樹很方便。簡單SQL語句用時10微秒之內,複雜SQL用時30微秒。
經過Druid提供的SQL Parser能夠在JDBC層攔截SQL作相應處理,好比說分庫分表、審計等。Druid防護SQL注入攻擊的WallFilter就是經過Druid的SQL Parser分析語義實現的 。
具體多看看官方文檔吧
列一張驕傲的官方圖就算簡介結束啦:
步驟(由上而下):
下面按照步驟上代碼。
1-2步,引入必須依賴。
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.5</version> </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>sqljdbc4</artifactId> <version>4.0</version> </dependency>
3.配置資源配置文件,創建druiddatasource
## druid
druid.datasource.enable-monitor=true
yw.order.druid.datasource.url=jdbc:sqlserver://172.16.20.1;DatabaseName=order
yw.order.druid.datasource.username=sa
yw.order.druid.datasource.password=WE+NBOPp+T9peFYfySpsw74OOvAwc095/4v51MUbF35cmECkaZMq7+
yw.order.druid.datasource.pwd-public-key=wSAJBALRv3R64ORcPJAik5KYZz+hxQAZJeSe9Pn8vJIOh8K01tHNk++zQBRQIVl7v+APbsWmPwAxvQ+OApl
yw.order.druid.datasource.initial-size=5
yw.order.druid.datasource.max-active=100
yw.order.druid.datasource.min-idle=5
yw.order.druid.datasource.slowSqlMillis=1000
package trade.user.api.config; import org.springframework.boot.context.properties.ConfigurationProperties; /** * @author zhanglonghao * @date 2019/7/17 11:13 */ @ConfigurationProperties(prefix = "yw.order.druid.datasource") public class MssqDataSourceProperties { /** * 數據源名稱 */ private String name; /** * 數據庫鏈接url */ private String url; /** * 數據庫用戶名 */ private String username; /** * 數據庫密碼 */ private String password; /** * 用來解密的密碼公鑰 */ private String pwdPublicKey; /** * 鏈接池初始鏈接數 */ private int initialSize = 5; /** * 鏈接池最大鏈接數 */ private int maxActive = 50; /** * 空閒的最小鏈接數量, 至關於線程池的最小鏈接數 */ private int minIdle = 5; /** * 獲取鏈接時最大等待時間,毫秒 */ private int maxWait = 60000; /** * 配置間隔多久才進行一次檢測須要關閉的空閒鏈接,單位是毫秒 ,默認1分鐘 */ private int timeBetweenEvictionRunsMillis = 60000; /** * 配置一個鏈接在池中最小生存的時間,超過該時間的空閒連接將被關閉,默認5分鐘 */ private int minEvictableIdleTimeMillis = 300000; /** * 驗證連接是否有效的sql */ private String validationQuery = "SELECT 'x'"; /** * 空閒時檢測連接是否有效 */ private boolean testWhileIdle = true; /** * 連接被借出時檢查是否有效,影響性能,默認關閉 */ private boolean testOnBorrow = false; /** * 當連接返還時檢查鏈接是否有效,影響性能,默認關閉 */ private boolean testOnReturn = false; /** * 是否緩存preparedStatement,也就是PSCache。PSCache對支持遊標的數據庫性能提高巨大,好比說oracle, * 在mysql下建議關閉。 */ private boolean poolPreparedStatements = false; /** * poolPreparedStatements爲false的狀況,該值不起做用 */ private int maxOpenPreparedStatements = 20; /** * 是否啓用數據源的監控,spring-web應用建議打開 */ private boolean enableMonitor = true; /** * 當啓用監控後, 是否打印慢sql */ private boolean logSlowSql = true; /** * 多少毫秒的sql認爲是慢sql, 默認1秒 */ private int slowSqlMillis = 1000; /** * 是否合併sql, 同一個PreparedStatements但where條件不一樣會被認爲是一個sql */ private boolean mergeSql = true; public String getName() { return name; } public void setName(String name) { this.name = name; } 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 getPwdPublicKey() { return pwdPublicKey; } public void setPwdPublicKey(String pwdPublicKey) { this.pwdPublicKey = pwdPublicKey; } public int getInitialSize() { return initialSize; } public void setInitialSize(int initialSize) { this.initialSize = initialSize; } public int getMaxActive() { return maxActive; } public void setMaxActive(int maxActive) { this.maxActive = maxActive; } public int getMinIdle() { return minIdle; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public int getMaxWait() { return maxWait; } public void setMaxWait(int maxWait) { this.maxWait = maxWait; } public int getTimeBetweenEvictionRunsMillis() { return timeBetweenEvictionRunsMillis; } public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) { this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } public int getMinEvictableIdleTimeMillis() { return minEvictableIdleTimeMillis; } public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } public String getValidationQuery() { return validationQuery; } public void setValidationQuery(String validationQuery) { this.validationQuery = validationQuery; } public boolean isTestWhileIdle() { return testWhileIdle; } public void setTestWhileIdle(boolean testWhileIdle) { this.testWhileIdle = testWhileIdle; } public boolean isTestOnBorrow() { return testOnBorrow; } public void setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; } public boolean isTestOnReturn() { return testOnReturn; } public void setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; } public boolean isPoolPreparedStatements() { return poolPreparedStatements; } public void setPoolPreparedStatements(boolean poolPreparedStatements) { this.poolPreparedStatements = poolPreparedStatements; } public int getMaxOpenPreparedStatements() { return maxOpenPreparedStatements; } public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) { this.maxOpenPreparedStatements = maxOpenPreparedStatements; } public boolean isEnableMonitor() { return enableMonitor; } public void setEnableMonitor(boolean enableMonitor) { this.enableMonitor = enableMonitor; } public boolean isLogSlowSql() { return logSlowSql; } public void setLogSlowSql(boolean logSlowSql) { this.logSlowSql = logSlowSql; } public int getSlowSqlMillis() { return slowSqlMillis; } public void setSlowSqlMillis(int slowSqlMillis) { this.slowSqlMillis = slowSqlMillis; } public boolean isMergeSql() { return mergeSql; } public void setMergeSql(boolean mergeSql) { this.mergeSql = mergeSql; } }
package trade.user.api.config; import com.alibaba.druid.filter.Filter; import com.alibaba.druid.filter.stat.StatFilter; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.List; /** * @author zhanglonghao * @date 2019/7/17 15:44 */ @Configuration @EnableConfigurationProperties({ MssqDataSourceProperties.class }) public class MssqlDataSource { @Autowired private MssqDataSourceProperties druidDataSourceProperties; @Bean(name = "OrderDruidDataSource", initMethod = "init", destroyMethod = "close") @ConditionalOnMissingBean(name = "OrderDruidDataSource") public DruidDataSource dashboardDruidDataSource() throws Exception { DruidDataSource result = new DruidDataSource(); result.setName(druidDataSourceProperties.getName()); result.setUrl(druidDataSourceProperties.getUrl()); result.setUsername(druidDataSourceProperties.getUsername()); result.setPassword(druidDataSourceProperties.getPassword()); result.setConnectionProperties( "config.decrypt=true;config.decrypt.key=" + druidDataSourceProperties.getPwdPublicKey()); result.setFilters("config"); result.setMaxActive(druidDataSourceProperties.getMaxActive()); result.setInitialSize(druidDataSourceProperties.getInitialSize()); result.setMaxWait(druidDataSourceProperties.getMaxWait()); result.setMinIdle(druidDataSourceProperties.getMinIdle()); result.setTimeBetweenEvictionRunsMillis(druidDataSourceProperties.getTimeBetweenEvictionRunsMillis()); result.setMinEvictableIdleTimeMillis(druidDataSourceProperties.getMinEvictableIdleTimeMillis()); result.setValidationQuery(druidDataSourceProperties.getValidationQuery()); result.setTestWhileIdle(druidDataSourceProperties.isTestWhileIdle()); result.setTestOnBorrow(druidDataSourceProperties.isTestOnBorrow()); result.setTestOnReturn(druidDataSourceProperties.isTestOnReturn()); result.setPoolPreparedStatements(druidDataSourceProperties.isPoolPreparedStatements()); result.setMaxOpenPreparedStatements(druidDataSourceProperties.getMaxOpenPreparedStatements()); if (druidDataSourceProperties.isEnableMonitor()) { StatFilter filter = new StatFilter(); filter.setLogSlowSql(druidDataSourceProperties.isLogSlowSql()); filter.setMergeSql(druidDataSourceProperties.isMergeSql()); filter.setSlowSqlMillis(druidDataSourceProperties.getSlowSqlMillis()); List<Filter> list = new ArrayList<Filter>(); list.add(filter); result.setProxyFilters(list); } return result; } }
note:上面有個小插曲就是根據druid生成密碼,命令:D:\Maven\repository\com\alibaba\druid\1.1.5> java -cp .\druid-1.1.5.jar com.alibaba.druid.filter.config.ConfigTools 密碼
5.餘下流程
1.使用PreparedStatement
@Autowired DruidDataSource dataSource; @RequestMapping(value = "/GetUserDetails") public String GetUserDetails(int userid) { try { // 得到鏈接: DruidPooledConnection conn = dataSource.getConnection(); // 編寫SQL: String sql = "select * from orderdiscount where pkid=? and orderid=?"; PreparedStatement pstmt = conn.prepareStatement(sql); //索引從1開始 pstmt.setLong(1,1L); pstmt.setInt(1,66666666); // 執行sql: ResultSet rs = pstmt.executeQuery(); while (rs.next()) { System.out.println(rs.getInt("PKID") + " " + rs.getString("OrderID")); } pstmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } return ""; }
2.使用Statement
@Autowired DruidDataSource dataSource; @RequestMapping(value = "/GetUserDetails") public String GetUserDetails(int userid) { try { // 得到鏈接: DruidPooledConnection conn = dataSource.getConnection(); // 編寫SQL: String sql = "select * from orderdiscount where pkid=1"; Statement pstmt = conn.createStatement(); // 執行sql: ResultSet rs = pstmt.executeQuery(sql); while (rs.next()) { System.out.println(rs.getInt("PKID") + " " + rs.getString("OrderID")); } pstmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } return ""; }
Statement和PreparedStatement的異同及優缺點
同:二者都是用來執SQL語句的
異:PreparedStatement須要根據SQL語句來建立,它可以經過設置參數,指定相應的值,不是像Statement那樣使用字符串拼接的方式。
PreparedStatement的優勢:
一、其使用參數設置,可讀性好,不易記錯。在statement中使用字符串拼接,可讀性和維護性比較差。
二、其具備預編譯機制,性能比statement更快。
三、其可以有效防止SQL注入攻擊。
execute和executeUpdate的區別
相同點:兩者都可以執行增長、刪除、修改等操做。
不一樣點:
一、execute能夠執行查詢語句,而後經過getResult把結果取出來。executeUpdate不能執行查詢語句。
二、execute返回Boolean類型,true表示執行的是查詢語句,false表示執行的insert、delete、update等。executeUpdate的返回值是int,表示有多少條數據受到了影響。
mybatis網上教程很對,這裏複製一段直接上代碼啦。
@MapperScan(value = { "trade.user.dal.dataobject", "trade.user.dal.mapper" }, sqlSessionFactoryRef = "OrderSqlSessionFactory") @ConditionalOnProperty(name = "yw.order.druid.datasource.url", matchIfMissing = false) public class MssqlDataSource { static final String MAPPER_LOCATION = "classpath*:sqlconfig/*Mapper.xml"; @Bean(name = "OrderSqlSessionFactory") @ConditionalOnMissingBean(name = "OrderSqlSessionFactory") public SqlSessionFactory sqlSessionFactory(@Qualifier("OrderDruidDataSource") DruidDataSource druidDataSource) throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(druidDataSource); sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION)); SqlSessionFactory sqlSessionFactory = sessionFactory.getObject(); sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true); return sqlSessionFactory; } }
@MapperScan("trade.user.**") public class StartMain { public static void main(String[] args) { SpringApplication.run(StartMain.class, args); } }
@Resource OrderDiscountDOMapper orderDiscountDOMapper; @RequestMapping(value = "/getInfo") public String getInfo(int id) { OrderDiscountDO rt=orderDiscountDOMapper.selectByPrimaryKey(1L); return id+"----"+ JSON.toJSONString(rt); }
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.1.6.RELEASE</version> </dependency>
88