JDBC與Druid簡單介紹及Druid與MyBatis鏈接數據庫

序言

java程序與數據創建鏈接,首先要從jdbc提及,而後直接上阿里認爲宇宙最好的數據庫鏈接池druid,而後再說上層程序對象與數據源映射關聯關係的orm-mybatis。java

JDBC介紹

JDBC(Java DataBase Connectivity)是Java和數據庫(關係型數據庫)之間的一個橋樑。mysql

  1. 是一個規範而不是一個實現,可以執行SQL語句。
  2. 它由一組用Java語言編寫的類和接口組成,各類不一樣類型的數據庫都有相應的實現。
  3. 它不屬於某一個數據庫的接口,而是能夠用於定義程序與數據庫鏈接規範,經過一整套接口,由各個不一樣的數據庫廠商去完成所對應的實現類,由sun公司提出! 

執行sql過程爲:類加載-->獲取鏈接-->書寫SQL-->執行語句--->處理結果集。git

爲何會有鏈接池的存在?github

由於創建數據庫鏈接是一個很是耗時、耗資源的行爲,因此經過鏈接池預先同數據庫創建一些鏈接,放在內存中,應用程序須要創建數據庫鏈接時直接到鏈接池中申請一個就行,用完後再放回去,極大的提升了數據庫鏈接的性能問題,節省了資源和時間。web

什麼是數據源spring

JDBC2.0 提供了javax.sql.DataSource接口,它負責創建與數據庫的鏈接,當在應用程序中訪問數據庫時 沒必要編寫鏈接數據庫的代碼,直接引用DataSource獲取數據庫的鏈接對象便可。用於獲取操做數據Connection對象。sql

數據源與數據庫鏈接池組件數據庫

數據源創建多個數據庫鏈接,這些數據庫鏈接會保存在數據庫鏈接池中,當須要訪問數據庫時,只須要從數據庫鏈接池中api

獲取空閒的數據庫鏈接,當程序訪問數據庫結束時,數據庫鏈接會放回數據庫鏈接池中。緩存

經常使用的數據庫鏈接池技術:

這些鏈接技術都是在jdbc的規範之上創建完成的。有以下:

C3P0、DBCP、Proxool和DruidX

Druid簡介及簡單使用實例

官方網站文檔: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分析語義實現的 。

具體多看看官方文檔吧

列一張驕傲的官方圖就算簡介結束啦:

使用Druid實現對MSSQL數據庫進行增刪查

步驟(由上而下):

  1. 引入druid依賴
  2. 引入com.microsoft.sqlserver.sqldjbc4依賴(由此依賴能夠看出JDBC與druid的關係,druid是基於jdbc規範創建的上層應用)
  3. 寫代碼
  4. 配置druid的datasource
  5. 創建Connection
  6. 建立Statement或者PreparedStatement接口執行SQL
  7. 處理結果
  8. 釋放資源

下面按照步驟上代碼。

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,表示有多少條數據受到了影響。

使用Druid與MyBatis構建程序與數據庫關聯關係及數據與程序實體映射

mybatis網上教程很對,這裏複製一段直接上代碼啦。

MyBatis 是支持普通 SQL 查詢,存儲過程和高級映射的優秀持久層框架。MyBatis 消除 了幾乎全部的 JDBC 代碼和參數的手工設置以及結果集的檢索。MyBatis 使用簡單的 XML 或註解用於配置和原始映射,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 對象)映射成數據庫中的記錄。

每一個MyBatis應用程序主要都是使用SqlSessionFactory實例的,一個SqlSessionFactory實例能夠經過SqlSessionFactoryBuilder得到。SqlSessionFactoryBuilder能夠從一個xml配置文件或者一個預約義的配置類的實例得到。  
 
用xml文件構建SqlSessionFactory實例是很是簡單的事情。推薦在這個配置中使用類路徑資源(classpath resource),但你可使用任何Reader實例,包括用文件路徑或file://開頭的url建立的實例。MyBatis有一個實用類----Resources,它有不少方法,能夠方便地從類路徑及其它位置加載資源。  
 
MyBatis 最強大的特性之一就是它的動態語句功能。若是您之前有使用JDBC或者相似框架的經歷,您就會明白把SQL語句條件鏈接在一塊兒是多麼的痛苦,要確保不能忘記空格或者不要在columns列後面省略一個逗號等。動態語句可以徹底解決掉這些痛苦。儘管與動態SQL一塊兒工做不是在開一個party,可是MyBatis確實能經過在任何映射SQL語句中
@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 

相關文章
相關標籤/搜索