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 密码

之后版本 

 public static void main(String[] args) throws Exception {
        String[] strs = new String[]{"Tuhumima123%]"};
        com.alibaba.druid.filter.config.ConfigTools.main(strs);
    } 

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 

posted @ 2019-07-18 15:32  张龙豪  阅读(34345)  评论(0编辑  收藏  举报