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


序言

java程序與數據建立連接,首先要從jdbc說起,然后直接上阿里認為宇宙最好的數據庫連接池druid,然后再說上層程序對象與數據源映射關聯關系的orm-mybatis。

JDBC介紹

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

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

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

為什么會有連接池的存在?

因為建立數據庫連接是一個非常耗時、耗資源的行為,所以通過連接池預先同數據庫建立一些連接,放在內存中,應用程序需要建立數據庫連接時直接到連接池中申請一個就行,用完后再放回去,極大的提高了數據庫連接的性能問題,節省了資源和時間。

什么是數據源

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

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

數據源建立多個數據庫連接,這些數據庫連接會保存在數據庫連接池中,當需要訪問數據庫時,只需要從數據庫連接池中

獲取空閑的數據庫連接,當程序訪問數據庫結束時,數據庫連接會放回數據庫連接池中。

常用的數據庫連接池技術:

這些連接技術都是在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的優點:

1、其使用參數設置,可讀性好,不易記錯。在statement中使用字符串拼接,可讀性和維護性比較差。

2、其具有預編譯機制,性能比statement更快。

3、其能夠有效防止SQL注入攻擊。

execute和executeUpdate的區別

相同點:二者都能夠執行增加、刪除、修改等操作。

不同點:

1、execute可以執行查詢語句,然后通過getResult把結果取出來。executeUpdate不能執行查詢語句。

2、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 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM