• 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 epositorycomalibabadruid1.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 

  • 相关阅读:
    python 获取浏览器窗口句柄
    实现远程连接 Win10的Ubuntu子系统下的MySQL数据库
    Postman 测试微信小程序后台接口
    使用Postman获取小程序码时如何解决47001报错
    富文本编辑框比较
    PIL 生成随机验证码图片
    哪里买书合算
    在文件中读取列表功能
    python函数01
    修改文件内容
  • 原文地址:https://www.cnblogs.com/knowledgesea/p/11202918.html
Copyright © 2020-2023  润新知