jdbc

作者: 帅哥_刷哥 | 来源:发表于2017-10-10 23:45 被阅读22次

    0.其它

    jdbc.url=jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=UTF8&allowMultiQueries=true
    jdbc:mysql:///hib_demo?createDatabaseIfNotExist=true
    

    1.jdbc概述

    数据库驱动
    JDBC是Java数据库连接技术的简称,提供连接各种常用数据库的能力
    SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。
    Sun公司为简化数据库开发,定义了一套jdbc接口,这套接口由数据库厂商去实现,这样,开发人员只需要学习jdbc接口,并通过jdbc加载具体的驱动,就可以操作数据库。
    JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成。
    组成JDBC的2个包:
        java.sql
        javax.sql
    开发JDBC应用需要以上2个包的支持外,还需要导入相应JDBC的数据库实现(即数据库驱动)。
    

    2.jdbc作用

    使用java代码操作数据库
    

    3.jdbc连接模式

    因为市面上有很多不同的数据库,那么对于开发人员来说,就要学习不同的数据库驱动来操作不同的数据库。如果数据库更新了,驱动也有可能更新,学习成本太高。
    那么有了jdbc以后,开发者就不用学习那么多数据库驱动了,只需要学习jdbc即可。
    jdbc是接口,是规范,由数据库厂商去开发具体的实现。
    

    4.jdbc开发步骤

    1.导入数据库驱动jar包
    2.注册驱动程序
    3.获取数据库连接
    4.创建Statement对象
    5.使用Statement对象来发送sql语句
    6.得到结果,处理结果
    7.关闭连接
    

    5.mysql使用

    //1.导入数据库驱动jar包
    // mysql-connector-java-5.1.7-bin.jar
    //2.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库连接
    String url = "jdbc:mysql://localhost:3306/test";
    String username="root";
    String password="root";
    Connection connection = DriverManager.getConnection(url, username, password);
    //4.创建Statement对象
    Statement statement = connection.createStatement();
    //5.使用Statement对象来发送sql语句
    String sql = "create table student(id int primary key auto_increment,name varchar(20),age int)";
    int count = statement.executeUpdate(sql);
    //6.得到结果,处理结果
    System.out.println("影响了"+count+"行");
    //7.关闭连接
    statement.close();
    connection.close();
    

    5.jdbc的详细体系

    1.jdbc接口存放位置:java.sql.*  javax.sql.*
    2.核心接口
        DriverManager
            用于加载驱动,并创建与数据库的链接
            注意:在实际开发中并不推荐采用registerDriver方法注册驱动。原因有二:
                一、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
                二、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
            推荐方式:Class.forName(“com.mysql.jdbc.Driver”);
                采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。
        Driver接口 : 驱动程序接口,使用驱动程序可以连接数据库
            如果DriverManager.registerDriver(new com.mysql.jdbc.Driver());这样写等于注册两次。看源码里面有静态代码块。
            所以 Class.forName("com.mysql.jdbc.Driver");就是在加载Driver中的静态代码块,这样就等于注册了。
        Connection接口 : 代表一个数据库连接
            它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。
            Connection的使用原则是尽量晚创建,尽量早的释放。
            为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
        Statement接口 : 用来执行静态sql语句
        PreparedStatement接口 : 用来执行预编译sql语句
        CallableStatement接口 : 用来执行存储过程的sql语句
        ResultSet接口 : 代表数据库的结果集
            Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。
            ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,
            可以使游标指向具体的数据行,进行调用方法获取该行的数据。
    

    6.常用数据类型转换表

    image.png

    7.增加

    //1.导入数据库驱动jar包
    // mysql-connector-java-5.1.7-bin.jar
    //2.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库连接
    String url = "jdbc:mysql://localhost:3306/test";
    String username="root";
    String password="root";
    Connection connection = DriverManager.getConnection(url, username, password);
    //4.创建Statement对象
    Statement statement = connection.createStatement();
    //5.使用Statement对象来发送sql语句
    String sql = "insert into student(name,age) values ('张三',20)";
    int count = statement.executeUpdate(sql);
    //6.得到结果,处理结果
    System.out.println("影响了"+count+"行");
    //7.关闭连接
    statement.close();
    connection.close();
    

    8.修改

    //1.导入数据库驱动jar包
    // mysql-connector-java-5.1.7-bin.jar
    //2.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库连接
    String url = "jdbc:mysql://localhost:3306/test";
    String username="root";
    String password="root";
    Connection connection = DriverManager.getConnection(url, username, password);
    //4.创建Statement对象
    Statement statement = connection.createStatement();
    //5.使用Statement对象来发送sql语句
    String sql = "update student set age=30 where id = 1";
    int count = statement.executeUpdate(sql);
    //6.得到结果,处理结果
    System.out.println("影响了"+count+"行");
    //7.关闭连接
    statement.close();
    connection.close();
    

    9.删除

    //1.导入数据库驱动jar包
    // mysql-connector-java-5.1.7-bin.jar
    //2.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库连接
    String url = "jdbc:mysql://localhost:3306/test";
    String username="root";
    String password="root";
    Connection connection = DriverManager.getConnection(url, username, password);
    //4.创建Statement对象
    Statement statement = connection.createStatement();
    //5.使用Statement对象来发送sql语句
    String sql = "delete from student where id = 1";
    int count = statement.executeUpdate(sql);
    //6.得到结果,处理结果
    System.out.println("影响了"+count+"行");
    //7.关闭连接
    statement.close();
    connection.close();
    

    10.查询

    //1.导入数据库驱动jar包
    // mysql-connector-java-5.1.7-bin.jar
    //2.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库连接
    String url = "jdbc:mysql://localhost:3306/test";
    String username="root";
    String password="root";
    Connection connection = DriverManager.getConnection(url, username, password);
    //4.创建Statement对象
    Statement statement = connection.createStatement();
    //5.使用Statement对象来发送sql语句
    String sql = "select * from student";
    //6.得到结果,处理结果
    ResultSet resultSet = statement.executeQuery(sql);
    while(resultSet.next()){
        int id = resultSet.getInt(1);
        String name = resultSet.getString(2);
        int age = resultSet.getInt(3);
        System.out.println(id+"-"+name+"-"+age);
    }
    //7.关闭连接
    statement.close();
    connection.close();
    

    11.数据库分页

    Select * from table limit M,N 
        M:记录开始索引位置,从0开始
        N:取多少条记录。
    

    12.jdbc封装

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    public class JDBCUtil {
        private static final String url = "jdbc:mysql://localhost:3306/test";
        private static final String username = "root";
        private static final String password = "root";
        static{
            try {
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        public static Connection getConnection(){
            try {
                Connection connection = DriverManager.getConnection(url, username, password);
                return connection;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        } 
        public static void close(ResultSet resultSet,Statement statement,Connection connection){
            if(resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    13.PreparedStatement预编译

    //?代表一个参数的占位,预编译验证sql是否正确
    PreparedStatement prepareStatement = connection.prepareStatement("insert into student(id,name,age) values(?,?,?)");
    //给参数赋值
    prepareStatement.setInt(1,1);
    prepareStatement.setString(2,"shuaige");
    prepareStatement.setInt(3, 30);
    //把参数发送给数据库
    int count = prepareStatement.executeUpdate();
    System.out.println("影响了"+count+"行");
    

    14.PreparedStatement和Statement的区别

    语法:
        Statement对象只支持静态sql,而PreparedStatement即支持静态sql也支持预编译sql
    执行效率
        PreparedStatement对象比Statement对象执行sql的效率会高。因为PreparedStatement可以利用数据库的sql缓存。
        
        Statement发送sql到数据库
            1)校验sql的语法,如果不合法就报错
            2)校验sql的执行权限,如果没有权限就报错。
            3)执行sql
                sql缓存区:先在sql缓存区查询是否已经执行过此sql,如果执行过,则取出对应的执行任务执行,
                如果没有执行过,则创建新的执行任务执行,把当前的sql放入缓存区。 
        PreparedStatement发送sql到数据库
            1)先发送sql到数据库
            2)发送占位的数据到数据库
            以后就只需要发送占位的数据到数据库就可以了。在mysql不明显,在Oracle才明显。
    安全问题
        Statement对象相对不安全。因为可以被sql注入。
        PreparedStatement能够防止sql注入。
    结论:尽量使用PreparedStatement。
        select * from users where name='shuaige' and password='1234';
        select * from users where 1=1;
        select * from users where name='随便写' or 1=1 --' and password='1234'
    

    15.执行存储过程CallableStatement

    //1.带有输入参数的存储过程
    //支持预编译
    CallableStatement callableStatement = connection.prepareCall("call pro_test(?)");
    callableStatement.setInt(1, 1);
    ResultSet resultSet = callableStatement.executeQuery();
    
    
    //2.带有输出参数的存储过程
    //支持预编译
    CallableStatement callableStatement = connection.prepareCall("call pro_test1(?)");
    //把某个参数注册为输出参数
    callableStatement.registerOutParameter(1, java.sql.Types.VARCHAR);
    //执行存储过程
    callableStatement.executeQuery();
    //取出输出参数的值
    String text = callableStatement.getString(1);
    

    16.jdbc核心类图

    image.png

    17.url写法

    //程序连接数据库的时候用UTF-8编码
    ?useUnicode=true&characterEncoding=UTF-8
    

    18.读取配置文件获取数据库配置信息

    //1.jdbc.properties代码
    url=jdbc:mysql://localhost:3306/test
    username=root
    password=root
    driverclass=com.mysql.jdbc.Driver
    
    //2.读取代码
    private static  String url = null;
    private static  String username = null;
    private static  String password = null;
    private static  String driverclass = null;
    static{
        Properties prop = new Properties();
        //JDBCUtil.class.getResourceAsStream 获得的是当前文件所在的包的src根目录
        InputStream inputStream = JDBCUtil.class.getResourceAsStream("/jdbc.properteis");
        try {
            prop.load(inputStream);
            url = prop.getProperty("url");
            username = prop.getProperty("username");
            password = prop.getProperty("password");
            driverclass = prop.getProperty("driverclass");
            Class.forName(driverclass);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    19.jdbc批处理

    1)作用
        一次发送多条sql语句,从而提高数据库执行sql的效率。
    2)批处理
        Statement
            addBatch方法 :添加sql到缓存
            excuteBatch方法 :发送缓存的所有sql语句到数据库执行
            clearBatch方法 :清空缓存的所有sql语句
        PreparedStatement
            addBatch方法 : 把一组参数添加到缓存
            executeBatch方法 :发送缓存的所有参数到数据库执行
            clearBatch方法 :清空缓存的所有参数
    3)需求
        使用Statement直接插入
        使用Statement+批处理插入
        使用PreparedStatement直接插入
        使用PreparedStatement+批处理插入
        
        结论:Oracle对PreparedStatement和批处理的支持比较好,但是mysql的支持并不明显。
    

    20.jdbc获取自增长的值

    //1.导入数据库驱动jar包
    // mysql-connector-java-5.1.7-bin.jar
    //2.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库连接
    String url = "jdbc:mysql://localhost:3306/test";
    String username="root";
    String password="root";
    Connection connection = DriverManager.getConnection(url, username, password);
    //4.创建PreparedStatement
    String sql = "insert into demp(name) values(?)";
    PreparedStatement prepareStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
    prepareStatement.setString(1,"shuaige");
    prepareStatement.executeUpdate();
    ResultSet resultSet = prepareStatement.getGeneratedKeys();
    int deptId = 0;
    if(resultSet.next()){
        deptId = resultSet.getInt(1);
    }
    sql = "insert into user(name,deptno) values(?,?)";
    PreparedStatement prepareStatement2 = connection.prepareStatement(sql);
    prepareStatement2.setString(1, "shuaige");
    prepareStatement2.setInt(2,deptId);
    prepareStatement2.executeUpdate();
    

    21.jdbc处理文件(字符和字节)数据

    1)分类
        字符文件:txt html xml
            mysql : tinytext text(64k) mediumtext(16M) longtext(4G)
            oracle : clob
        字节文件:二进制,图片,视频,zip。。
            mysql : tinyblob blob(64k) mediumblob(16M) longblob(4G)
            oracle : blob
    2)写入字符文件的代码
        //1.导入数据库驱动jar包
        // mysql-connector-java-5.1.7-bin.jar
        //2.注册驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //3.获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test";
        String username="root";
        String password="root";
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.创建PreparedStatement
        String sql = "insert into article(name,content) values(?,?)";
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        File file = new File("D:\\test.txt");
        FileReader reader = new FileReader(file);
        prepareStatement.setString(1,file.getName());
        prepareStatement.setClob(2, reader);
        prepareStatement.executeUpdate();
    3)读取字符文件的代码
        //1.导入数据库驱动jar包
        // mysql-connector-java-5.1.7-bin.jar
        //2.注册驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //3.获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test";
        String username="root";
        String password="root";
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.创建PreparedStatement
        String sql = "select name,content from article where id = 1";
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        ResultSet resultSet = prepareStatement.executeQuery();
        if(resultSet.next()){
            Clob clob = resultSet.getClob("content");
            Reader reader = clob.getCharacterStream();
            //写出到硬盘即可
        }
    4)写入字节文件的代码
        //1.导入数据库驱动jar包
        // mysql-connector-java-5.1.7-bin.jar
        //2.注册驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //3.获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test";
        String username="root";
        String password="root";
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.创建PreparedStatement
        String sql = "insert into images(content) values(?)";
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        File file = new File("D:\\shuaige.png");
        FileInputStream input = new FileInputStream(file);
        prepareStatement.setBlob(1, input);
        prepareStatement.executeUpdate();
    5)读取字节文件的代码
        //1.导入数据库驱动jar包
        // mysql-connector-java-5.1.7-bin.jar
        //2.注册驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //3.获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test";
        String username="root";
        String password="root";
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.创建PreparedStatement
        String sql = "select content from images where id = 1";
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        ResultSet resultSet = prepareStatement.executeQuery();
        if(resultSet.next()){
            Blob blob = resultSet.getBlob(1);
            InputStream inputStream = blob.getBinaryStream();
            //写出到硬盘
        }
    

    22.jdbc时间处理

    //1.导入数据库驱动jar包
    // mysql-connector-java-5.1.7-bin.jar
    //2.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库连接
    String url = "jdbc:mysql://localhost:3306/test";
    String username="root";
    String password="root";
    Connection connection = DriverManager.getConnection(url, username, password);
    //4.创建PreparedStatement
    String sql = "insert into timetest(logintime) values(?)";
    PreparedStatement prepareStatement = connection.prepareStatement(sql);
    prepareStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
    prepareStatement.setTimestamp(1, new Timestamp(new java.util.Date().getTime()));
    prepareStatement.executeUpdate();
    

    23.jdbc事务

    1)概念
        如果把(多条)sql语句看做是一个事务,那么这个事务里面的操作要么一起成功过,要么一起失败。
    2)数据库的事务功能
        数据库的类型innoDB才能完全支持事务。
    3)数据库的事务命令
        set autocommit=0; 开始事务(关闭自动提交事务的功能。默认值1,自动提交事务 0,关闭自动提交)
        commit 提交事务,一旦事务提交了,就不能回滚了。
        rollback 回滚事务。回滚到事务的开始位置。
    3)sql命令
        set autocommit=0;
    4)代码
        //1.导入数据库驱动jar包
        // mysql-connector-java-5.1.7-bin.jar
        //2.注册驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //3.获取数据库连接
        String url = "jdbc:mysql://localhost:3306/test";
        String username="root";
        String password="root";
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.创建PreparedStatement 
        String sql = "update account set money = money-1000 where name='jack'";
        String sql1 = "update account set money = money+1000 where name='rose'";
        connection.setAutoCommit(false);
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        prepareStatement.executeUpdate();
        //报错
        PreparedStatement prepareStatement2 = connection.prepareStatement(sql1);
        prepareStatement2.executeUpdate();
        connection.commit();
        //异常中回滚 rollback();
    5)事务使用的场景
        一个业务操作里面存在多条的更新类语句(DML语句)
    6)事务的四个特征
        原子性 (A)Atomicity
            事务是一个不可分割的单元,要么一起成功,要么一起失败
        一致性 (C)Consistency
            事务必须使数据库从一个一致性状态变换到另外一个一致性状态
        隔离性 (I)Isolation
            多个事务并发操作之间应该要相互隔离的
                如果多个事务之间没有隔离,则会产生以下现象:
                    1)脏读
                        一个事务读到了另一个事务未提交的更新数据
                    2)不可重复读
                        一个事务读到了另一个事务已经更新的数据
                    3)幻读
                        一个事务读到了另一个事务已经提交的插入数据
                数据库的4个隔离级别来防止以上现象
                    serializable 最高级别 不支持脏读,不可重复读,幻读
                    repeatable read不支持脏读,不可重复读.支持幻读(mysql默认)
                    read committed 不支持脏读.支持不可重复读,幻读(Oracle默认)
                    read uncommitted 最低级别 支持脏读,不可重复读,幻读
                mysql查看事务的隔离级别
                    select @@global.tx_isolation;(全局)
                    select @@tx_isolation;(会话)
                mysql修改事务的隔离级别
                    set global transaction isolation level read committed;(全局)
                    set session transaction isolation level uncommitted;(会话)
                    
                数据库隔离级别越高,安全性越高,数据库并发性能越低。
        持久性 (D)Durability
            事务一旦提交,数据永远保存下来
    

    24.连接优化

    为什么需要连接池
        访问前需要先获取连接
        每次操作结束后,要释放资源
        频繁的连接导致系统的安全性和稳定性差
    工作原理
        连接池是由容器提供的,用来管理池中连接对象
        连接池自动分配连接对象并对闲置的连接进行回收
    
    1)作用
        1.提高Connection对象的利用率(一个Connection对象可以多次操作)
        2.控制Connection对象的数量,保证数据库服务器的安全
        
        引入连接池的概念来实现以上的功能
    2)连接池
        sun设计了一个接口 javax.sql.DataSource 是所有连接池实现的接口
            getConnection 从连接池中获取连接的方法
            
    

    25.jdbc优化-自定义连接池

    public class MyDataSource implements DataSource {
        
        public static LinkedList<Connection> pool = new LinkedList<Connection>();
        
        private int initCount = 5;
        private int maxCount = 10;
        private int currentCount=0;
        
        private static String url = "jdbc:mysql://localhost:3306/test";
        private static String user = "root";
        private static String password = "root";
        private static String driverClass = "com.mysql.jdbc.Driver";
        
        static{
            try {
                Class.forName(driverClass);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        
        private static Connection createConnection(){
            try {
                return DriverManager.getConnection(url, user, password);
            } catch (SQLException e) {
            }
            return null;
        }
        
        public MyDataSource() {
            for(int i = 0;i<initCount;i++){
                pool.add(createConnection());
                currentCount++;
            }
        }
    
        @Override
        public Connection getConnection() throws SQLException {
            if(pool.size()>0){
                //从池中取出并且返回一个连接
                return pool.removeFirst();
            }else{
                if(currentCount<maxCount){
                    currentCount++;
                    return createConnection();
                }
                throw new RuntimeException("超出最大连接数");
            }
        }
    
        public static void release(Connection conn){
            pool.addLast(conn);
        }
    }
    

    26.jdbc优化-自定义连接池优化-代理

    代理模式的要数
        代理接口:代理类和被代理类共同的行为
        被代理类:需要被代理的类
        代理类:和被代理类有相同的接口,代理类可以有自己的实现
    
    静态代理和动态代理
    

    27.jdbc优化-自定义连接池优化-静态代理

    特点是代理类是由开发者自行编写
    步骤:
        1实现和被代理类相同的接口
        2声明一个接口成员变量
        3在代理类的构造方法中接收被代理类实例
        4在代理类的方法中实现自己的逻辑
        
    处理自定义连接池的close方法
    
    public class MyDataSource implements DataSource {
        public static LinkedList<Connection> pool = new LinkedList<Connection>();
        private int initCount = 5;
        private int maxCount = 10;
        private int currentCount=0;
        private static String url = "jdbc:mysql://localhost:3306/test";
        private static String user = "root";
        private static String password = "root";
        private static String driverClass = "com.mysql.jdbc.Driver";
        static{
            try {
                Class.forName(driverClass);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        private Connection createConnection(){
            try {
                Connection connection = DriverManager.getConnection(url, user, password);
                Connection proxy = new MyConnectionProxy(connection, this);
                return proxy;
            } catch (SQLException e) {
            }
            return null;
        }
        public MyDataSource() {
            for(int i = 0;i<initCount;i++){
                pool.add(createConnection());
                currentCount++;
            }
        }
        @Override
        public Connection getConnection() throws SQLException {
            if(pool.size()>0){
                //从池中取出并且返回一个连接
                return pool.removeFirst();
            }else{
                if(currentCount<maxCount){
                    currentCount++;
                    return createConnection();
                }
                throw new RuntimeException("超出最大连接数");
            }
        }
        public static void release(Connection conn){
            pool.addLast(conn);
        }
    }
    
    public class MyConnectionProxy implements Connection{
        private Connection realConn;
        private MyDataSource datasource;
        public MyConnectionProxy(Connection realConn,MyDataSource datasource){
            this.realConn = realConn;
            this.datasource = datasource;
        }
        @Override
        public Statement createStatement() throws SQLException {
            return realConn.createStatement();
        }
        @Override
        public void close() throws SQLException {
            datasource.pool.addLast(this);
        }
    }
    

    28.jdbc优化-自定义连接池优化-动态代理

    特点是代理类是由程序生成的
    public class MyDataSource implements DataSource {
        public static LinkedList<Connection> pool = new LinkedList<Connection>();
        private int initCount = 5;
        private int maxCount = 10;
        private int currentCount=0;
        private static String url = "jdbc:mysql://localhost:3306/test";
        private static String user = "root";
        private static String password = "root";
        private static String driverClass = "com.mysql.jdbc.Driver";
        static{
            try {
                Class.forName(driverClass);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        private Connection createConnection(){
            try {
                final Connection connection = DriverManager.getConnection(url, user, password);
                Connection proxy = (Connection)Proxy.newProxyInstance(this.getClass().getClassLoader(), 
                        new Class[]{Connection.class}, 
                        new InvocationHandler() {
                            @Override
                            public Object invoke(Object newproxy, Method method, Object[] args) throws Throwable {
                                String name = method.getName();
                                if("close".equals(name)){
                                    pool.addLast((Connection)newproxy);
                                }else{
                                    return method.invoke(connection, args);
                                }
                                return null;
                            }
                        });
                return proxy;
            } catch (SQLException e) {
            }
            return null;
        }
        public MyDataSource() {
            for(int i = 0;i<initCount;i++){
                pool.add(createConnection());
                currentCount++;
            }
        }
        @Override
        public Connection getConnection() throws SQLException {
            if(pool.size()>0){
                //从池中取出并且返回一个连接
                return pool.removeFirst();
            }else{
                if(currentCount<maxCount){
                    currentCount++;
                    return createConnection();
                }
                throw new RuntimeException("超出最大连接数");
            }
        }
        public static void release(Connection conn){
            pool.addLast(conn);
        }
    }
    

    29.jdbc优化-dbcp连接池

    1)概述
        DBCP是Apache组织的工具,DataBase Connection Pool
        是Apache上的一个 java连接池项目,也是 tomcat使用的连接池组件
        下载 : 
            http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi
            http://commons.apache.org/proper/commons-pool/download_pool.cgi
            http://commons.apache.org/proper/commons-logging/download_logging.cgi
    2)使用步骤
        导入jar包
        创建连接池
        配置连接池参数
        获取连接
    3)1.4版本代码一
    //测试类
    public class Test {
        public static void main(String[] args) throws Exception {
            for(int i = 0;i<11;i++){
                Connection connection = DBCPUtil.getConnection();
                System.out.println(connection);
                //释放连接
                connection.close();
            }
        }
    }
    //工具类
    //commons-dbcp-1.4.jar/commons-pool-1.6.jar
    public class DBCPUtil {
        private static String url = "jdbc:mysql://localhost:3306/test";
        private static String user = "root";
        private static String password = "root";
        private static String driverClass = "com.mysql.jdbc.Driver";
        public static BasicDataSource datasource =null;
        static {
            datasource = new BasicDataSource();
            datasource.setUrl(url);
            datasource.setUsername(user);
            datasource.setPassword(password);
            datasource.setDriverClassName(driverClass);
            // 连接池参数配置
            // 初始化连接数
            datasource.setInitialSize(5);
            // 最大连接数
            datasource.setMaxActive(10);
            // 当超过最大连接后,最长等待时间
            datasource.setMaxWait(3000);
        }
        public static Connection getConnection(){
            try {
                return datasource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    //1.4版本代码二
    //dbcp.properties
    url=jdbc:mysql://localhost:3306/test
    username=root
    password=root
    driverClassName=com.mysql.jdbc.Driver
    initialSize=5
    maxActive=10
    maxWait=3000
    //commons-dbcp-1.4.jar/commons-pool-1.6.jar
    public class DBCPUtil {
        public static BasicDataSource datasource =null;
        static {
            Properties prop = new Properties();
            InputStream inputStream = DBCPUtil.class.getResourceAsStream("/dbcp.properties");
            try {
                prop.load(inputStream);
                datasource = (BasicDataSource) BasicDataSourceFactory.createDataSource(prop);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static Connection getConnection(){
            try {
                return datasource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public class Test {
        public static void main(String[] args) throws Exception {
            for(int i = 0;i<11;i++){
                Connection connection = DBCPUtil.getConnection();
                System.out.println(connection);
                //释放连接
                connection.close();
            }
        }
    }
    4)2.2.1版本代码一
    //dbcp.properties
    url=jdbc:mysql://localhost:3306/test
    username=root
    password=root
    driverClassName=com.mysql.jdbc.Driver
    initialSize=5
    maxActive=10
    maxWait=3000
    //commons-dbcp2-2.1.1.jar/commons-pool2-2.4.2.jar/commons-logging-1.2.jar
    public class DBCPUtil {
        public static BasicDataSource datasource =null;
        static {
            Properties prop = new Properties();
            InputStream inputStream = DBCPUtil.class.getResourceAsStream("/dbcp.properties");
            try {
                prop.load(inputStream);
                datasource = (BasicDataSource) BasicDataSourceFactory.createDataSource(prop);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static Connection getConnection(){
            try {
                return datasource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public class Test {
        public static void main(String[] args) throws Exception {
            for(int i = 0;i<11;i++){
                Connection connection = DBCPUtil.getConnection();
                System.out.println(connection);
                //释放连接
                connection.close();
            }
        }
    }
    //2.2.1代码二
    //commons-dbcp2-2.1.1.jar/commons-pool2-2.4.2.jar/commons-logging-1.2.jar
    public class DBCPUtil {
        private static String url = "jdbc:mysql://localhost:3306/test";
        private static String user = "root";
        private static String password = "root";
        private static String driverClass = "com.mysql.jdbc.Driver";
        public static BasicDataSource datasource =null;
        static {
            try {
                datasource = new BasicDataSource();
                datasource.setUrl(url);
                datasource.setUsername(user);
                datasource.setPassword(password);
                datasource.setDriverClassName(driverClass);
                datasource.setInitialSize(5);
                datasource.setMaxTotal(10);
                datasource.setMaxWaitMillis(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static Connection getConnection(){
            try {
                return datasource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public class Test {
        public static void main(String[] args) throws Exception {
            for(int i = 0;i<11;i++){
                Connection connection = DBCPUtil.getConnection();
                System.out.println(connection);
                //释放连接
                connection.close();
            }
        }
    }
    

    jdbc优化-c3p0连接池

    1)概述
        目前应用广泛的连接池工具之一。hibernate框架推荐使用的连接池
        C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。
        c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。
        扩展这些操作可以有效的提升性能。
        目前使用它的开源项目有Hibernate,Spring等。
        c3p0有自动回收空闲连接功能
        下载
            https://sourceforge.net/projects/c3p0/
    2)使用步骤
        导入jar包
        核心类 ComboPooledDataSource
    3)代码一
    //c3p0-0.9.5.2.jar/mchange-commons-java-0.2.11.jar
    public class C3P0Util {
        private static String url = "jdbc:mysql://localhost:3306/test";
        private static String user = "root";
        private static String password = "root";
        private static String driverClass = "com.mysql.jdbc.Driver";
        private static ComboPooledDataSource ds = null;
        static {
            ds = new ComboPooledDataSource();
            ds.setJdbcUrl(url);
            ds.setUser(user);
            ds.setPassword(password);
            try {
                ds.setDriverClass(driverClass);
            } catch (PropertyVetoException e) {
                e.printStackTrace();
            }
            ds.setInitialPoolSize(5);
            ds.setMaxPoolSize(10);
            ds.setCheckoutTimeout(3000);
        }
        public static Connection getConnection(){
            try {
                return ds.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public class Test {
        public static void main(String[] args) throws Exception {
            for(int i = 0;i<11;i++){
                Connection connection = C3P0Util.getConnection();
                System.out.println(connection);
                connection.close();
            }
        }
    }
    4)代码二
    // c3p0-config.xml
    <c3p0-config>
        <!-- 默认配置 -->
        <default-config>
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
            <property name="user">root</property>
            <property name="password">root</property>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="initialPoolSize">5</property>
            <property name="maxPoolSize">10</property>
            <property name="checkoutTimeout">3000</property>
        </default-config>
        <named-config name="intergalactoApp">
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
            <property name="user">root</property>
            <property name="password">root</property>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="initialPoolSize">5</property>
            <property name="maxPoolSize">10</property>
            <property name="checkoutTimeout">3000</property>
        </named-config>
    </c3p0-config>
    //c3p0-0.9.5.2.jar/mchange-commons-java-0.2.11.jar
    public class C3P0Util {
        private static ComboPooledDataSource ds = null;
        static {
            //读取默认配置default-config
            ds = new ComboPooledDataSource();
            //读取配置 named-config = intergalactoApp
            //ds = new ComboPooledDataSource("intergalactoApp");
        }
        public static Connection getConnection(){
            try {
                return ds.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public class Test {
        public static void main(String[] args) throws Exception {
            for(int i = 0;i<11;i++){
                Connection connection = C3P0Util.getConnection();
                System.out.println(connection);
                connection.close();
            }
        }
    }
    获取数据库元数据 DatabaseMetaData 得到数据库相关信息
        DatabaseMetaData dbmd = connection.getMetaData();
        System.out.println(dbmd.getDatabaseProductName());
        System.out.println(dbmd.getDatabaseMajorVersion());
        System.out.println(dbmd.getDatabaseMinorVersion());
        System.out.println(dbmd.getDriverName());
        System.out.println(dbmd.getDriverMajorVersion());
        System.out.println(dbmd.getDriverMinorVersion());
    参数元数据  ParameterMetaData 得到参数相关信息
    结果集元数据  ResultSetMetaData 得到结果集相关信息
    

    jdbc优化-Proxool连接池

    Proxool是一种Java数据库连接池技术。
    是sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,
    最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况
    

    jdbc优化-druid连接池

    Tomcat中配置数据源连接池

    在Tomcat中配置数据源
        在Tomcat中的conf/context.xml配置中的<Context></Context>元素下添加
            <Resource name="jdbc/shuaige" auth="Container" type="javax.sql.DataSource"
                maxActive="100" maxIdle="30" maxWait="10000" username="root" 
                password="root" driverClassName="com.mysql.jdbc.Driver"
                url="jdbc:mysql://localhost:3306/shuaige" />
            解释
                name:数据源名称
                type:指定管理者及数据源的类型
                maxActive:最大连接数
                maxWait:最长等待时间
                url:数据库路径
    在项目中读取数据源-JNDI读取数据源
        JNDI是Java命名与目录接口
        通过名称与对象的绑定实现资源获取
        代码:
            //初始化上下文
            Context cxt=new InitialContext();
            //获取与逻辑名相关联的数据源对象
            //通过Context接口的lookup()查找数据源
            //java:comp/env为JavaEE默认路径
            //jdbc/news为DataSource的名称
            DataSource ds=(DataSource)cxt.lookup("java:comp/env/jdbc/shuaige");
            conn=ds.getConnection();
    

    DBUtils工具(jdbc的简单封装)

    概述
        Apache组织的一个框架,是对jdbc简单的封装
    下载
        http://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi
    使用步骤
        导入jar包
             使用c3p0连接池 c3p0-0.9.5.2.jar/mchange-commons-java-0.2.11.jar
             commons-dbutils-1.7.jar
        核心类
            QueryRunner
    增加数据
        public static void insert() throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "insert into user (name,age) values(?,?)";
            Integer id = qr.insert(sql, new ResultSetHandler<Integer>() {
                @Override
                public Integer handle(ResultSet resultSet) throws SQLException {
                    resultSet.next();
                    return resultSet.getInt(1);
                }
            },new Object[]{"shuaige",32});
            System.out.println("返回的新id是:"+id);
        }
    更新数据
        public static void update() throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "update user set name = ? where id = ?";
            int count = qr.update(sql, new Object[]{"shuaigege",25});
            System.out.println("影响的记录数:"+count);
        }
    删除数据
        public static void delete() throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "delete from user where id = ?";
            int count = qr.execute(sql, new Object[]{1});
            System.out.println("影响的记录数:"+count);
        }
    查询数据
        public static void query()throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "select * from user";
            List<User> list = (List<User>)qr.query(sql,new ResultSetHandler(){
                @Override
                public Object handle(ResultSet resultSet) throws SQLException {
                    List<User> list = new ArrayList<User>();
                    while(resultSet.next()){
                        int id = resultSet.getInt("id");
                        String name = resultSet.getString("name");
                        int age = resultSet.getInt("age");
                        User user = new User(id,name,age);
                        list.add(user);
                    }
                    return list;
                }
            });
            System.out.println(list);
        }
        //BeanListHandler: 把结果集封装成一个List(javabean)
        public static void query()throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "select * from user";
            List<User> list = qr.query(sql,new BeanListHandler(User.class));
            System.out.println(list);
        }
        //BeanHandler: 把结果集封装成一个javabean
        public static void query()throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "select * from user where id = ?";
            User user = qr.query(sql,new BeanHandler(User.class),new Object[]{2});
            System.out.println(user);
        }
        //ArrayHandler: 把结果集的第一行封装成一个对象数组
        public static void query()throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "select * from user where id = ?";
            Object[] objArr = qr.query(sql,new ArrayHandler(),new Object[]{2});
            for(Object obj : objArr){
                System.out.println(obj);
            }
        }
        //ArrayListHandler: 把结果集封装成一个List(对象数组)
        public static void query()throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "select * from user where id = ?";
            List<Object[]> list = qr.query(sql,new ArrayListHandler(),new Object[]{2});
            for(Object[] objArr : list){
                for(Object obj :objArr){
                    System.out.print(obj);
                }
                System.out.println();
            }
        }
        //ScalarHandler: 处理聚合查询的结果集 count(*) max(xx) min(xxx)
        public static void query()throws Exception{
            QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
            String sql = "select count(*) from user";
            Long count = qr.query(sql,new ScalarHandler());
            System.out.println(count);
        }
    控制事务
        public static void useTransaction() throws Exception{
            Connection connection = C3P0Util.getConnection();
            connection.setAutoCommit(false);
            QueryRunner qr = new QueryRunner();
            try {
                String sql = "delete from user where id = ?";
                int count = qr.execute(connection,sql, new Object[]{1});
                System.out.println("影响的记录数:"+count);
                int a = 1/0;
                String sql1 = "update user set name = ? where id = ?";
                int count1 = qr.update(connection,sql1, new Object[]{"shuaigege",25});
                System.out.println("影响的记录数:"+count1);
                connection.commit();
            } catch (Exception e) {
                e.printStackTrace();
                connection.rollback();
            }finally {
                connection.close();
            }
        }
    

    其它

    持久化
        持久化是将程序中的数据在瞬时状态和持久状态间转换的机制
        操作:增加、删除、更新、查询
    DAO
        Data Access Object(数据存取对象)
        实现对持久化数据的访问
        DAO起着转换器的作用,把实体类转换为数据库中的记录
        写法:
            接口/实现类/实体类/数据库工具类
            
    分层开发
        特点:
            每一层都有自己的职责
            上一层不用关心下一层的实现细节,上一层通过下一层提供的对外接口来使用其功能
            上一层调用下一层的功能,下一层不能调用上一层功能
        好处:
            各层专注于自己功能的实现,便于提高质量
            便于分工协作,提高开发效率
            便于代码复用
            便于程序扩展
            便于提高开发质量、提高开发效率、便于代码复用、便于程序扩展、便于降低代码的耦合性。
            分层时应坚持封装性原则和顺序访问原则  
            不同层之间通过实体类传输数据
    

    ORM

    概述
        Object Relation Mapping
        对象关系映射
        R(数据库)     M          O(java)
           表        <->           类
          字段       <->          属性
        一条记录     <->        一个对象    
    ORM实现
        hibernate/mybatis/自己代码实现    
    

    双向关联(一对多)

    create table customer(
        id int primary key auto_increment,
        name varchar(20)
    );
    create table order(
        id int primary key auto_increment,
        orderno varchar(20),
        c_id int,
        constraint order_customer_fk foreign key(c_id) references customer(id)
    );
    public class Customer{
        private int id;
        private String name;
        private List<Order> orders = new ArrayList<Order>();
    }
    public class Order{
        private int id;
        private String orderno;
        private Customer customer;
    }
    public void save(){
        //1.保存用户
        insert into customer(name) values(?)
        //2.如果用户有关联订单,订单也一起保存
        for(Order order : customer.getOrders(){
            insert into order (orderno,c_id) values(?,?)
        }
    }
    public void query(){
        //1.查询用户
        select * from customer where id = ?
        //2.查询关联订单
        select * from order where c_id = ?
    }
    

    双向关联(多对多)

    create table teacher(
        id int primary key auto_increment,
        name varchar(20)
    );
    create table student(
        id int primary key auto_increment,
        name varchar(20)
    );
    create table teacher_student(
        t_id int,
        s_id int,
        constraint tea_stu_tea_fk foreign key(t_id) references teacher(id),
        constraint tea_stu_stu_fk foreign key(s_id) references student(id)
    );
    public class Teacher{
        private int id;
        private String name;
        private List<Student> students = new ArrayList<Student>();
    }
    public class Student{
        private int id;
        private String name;
        private List<Teacher> teachers = new ArrayList<Teacher>();
    }
    public void save(){
        //1.插入老师
        insert into teacher(name) values(?);
        //2.如果有学生也插入
        insert into student(name) values(?);
        //3.插入中间表
        insert into teacher_student(t_id,s_id) values(?,?)
    }
    public void query(){
        //1.查询老师
        select * from teacher where id = ?
        //2.关联查询
        select s.* from student s,teacher_student ts where s.id = ts.s_id and t_id=?
    }
    

    双向关联 一对一

    create table person(
        id int primary key auto_increment,
        name varchar(20)
    )
    create table idcard(
        id int primary key auto_increment,
        idno varchar(18),
        p_id int unique,
        constraint idcard_person_fk foreign key(p_id) references person(id)
    )
    public class Person{
        private int id;
        private String name;
        private IdCard idCard;
    }
    public class IdCard{
        private int id;
        private String idno;
        private Person person;
    }
    public void save(){
        //插入公民表
        insert into person (name) values(?)
        //插入身份证表
        insert into idcard (idno,p_id) values(?,?)
    }
    public void query(){
        //查询公民表
        select * from person where id = ?
        //查询身份证表
        select * from idcard where p_id = ?
    }
    

    相关文章

      网友评论

          本文标题:jdbc

          本文链接:https://www.haomeiwen.com/subject/qthnsxtx.html