• Java连接数据库JDBC


    前言

    在Python和Golang我们可以使用pip install和go get 去下载开发中使用到的开源的第三方包,以实现企业级应用的开发;

    在Java中使用一系列的JAR包通常用于归档大量的Java类文件、相关的元数据和资源(文本、图片等)文件到1个文件中,以便开发Java平台应用软件或库。

    帮助我们实现功能丰富、复杂的企业家应用开发;

    JAR(Java Archive/Java归档)包,不仅用于压缩和发布,而且还用于部署和封装库、组件和插件程序,并可被像编译器和 JVM 这样的工具直接使用。

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.mingde</groupId>
        <artifactId>_03_maven_jdbc</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <name>_03_maven_jdbc</name>
        <!--&lt;!&ndash; FIXME change it to the project's website &ndash;&gt;-->
        <!--<url>http://www.example.com</url>-->
        <packaging>jar</packaging>
        <description>MySQL数据库连接测试</description>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
        </properties>
    
        <dependencies>
            <!--junit依赖包-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <!-- jdbc依赖包https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.37</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.18</version>
                <scope>provided</scope>
            </dependency>
            <!--c3p0依赖包-->
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.5.2</version>
            </dependency>
            <!--druid依赖包-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.9</version>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <appendAssemblyId>false</appendAssemblyId>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <archive>
                            <manifest>
                                <!-- 此处指定main方法入口的class -->
                                <mainClass>com.mingde.jdbc.JdbcDemo1</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>assembly</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    pom.xml

    一、JDBC是什么?

    Java Database Connectivity简称JDBC,是Java官方(Sun公司)定义的一套Java程序操作所有关系型数据库的规范(接口)

    各大数据库厂商为了通过Java来推广自己的数据库产品,实现了JDBC规范(接口)并通过JAR包的形式发布出来给Java开发人员使用,就是数据库驱动(driver)。

    现在我们要用Java调MySQL数据库,所以就需要提前下载MySQL提供的的driver,也就是1个JAR包;

    二、JDBC数据库操作 

    DriverManager驱动管理对象:             可以获取数据库连接对象。
    Connection 数据库连接对象: 可以获取执行SQL的对象,可以管理事务操作。
    Statement 执行静态SQL对象: 可以执行数据库的增删改查操作
    PrepareStatement 执行预编译SQL对象: 可以执行带有?占位符的预编译SQL
    ResultSet 查询结果集对象: 保存封装了MySQL查询结果对象
     

    1.创建表(DML)

    package cn.zhanggen;
    
    import com.mysql.jdbc.CommunicationsException;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;
    public class App { public static void main(String[] args) { Connection connection = null; Statement statement = null; try { Class.forName("com.mysql.jdbc.Driver"); String dbURL = "jdbc:mysql://192.168.56.18:3306/web?characterEncoding=utf8"; connection = DriverManager.getConnection(dbURL, "zhanggen", "123.com"); statement = connection.createStatement(); String createTable="CREATE TABLE IF NOT EXISTS `staffs`(\n" + "`id` INT UNSIGNED AUTO_INCREMENT KEY COMMENT '用户编号',\n" + "`username` VARCHAR(20) NOT NULL UNIQUE COMMENT '用户名',\n" + "`age` TINYINT UNSIGNED NOT NULL DEFAULT 18 COMMENT '年龄',\n" + "`salary` FLOAT(8,2) NOT NULL DEFAULT 0 COMMENT '薪水'\n" + ")ENGINE=INNODB DEFAULT CHARSET=UTF8;"; statement.executeUpdate(createTable); // String sql = "insert into staffs(username,age,salary) values ('马睿',18,999.19),('张景辉',58,999.19);"; // statement.executeUpdate(sql); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { System.out.println("11"); e.printStackTrace(); } finally { if (statement != null) { try { statement.close(); connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }

    2.新增记录

    import java.sql.Connection;
    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    
    public class Insert01 {
        public static void main(String[] args) throws Exception {
            //1.将MySQL服务器提供的jar包中的Driver接口实现类,注册到JVM
            Driver driver = new com.mysql.jdbc.Driver();
            DriverManager.registerDriver(driver);
    
            //2.通过DriverManager在java工程和MySQL服务器之间建立1个连接通道;
            String dbURL = "jdbc:mysql://192.168.0.98:3306/zhanggen?characterEncoding=utf8";
            Connection conn = DriverManager.getConnection(dbURL, "yourusername", "yourpassword");
    
            //3.在通道中创建1个交通工具
            PreparedStatement ps = conn.prepareStatement("");
    
            //4.通过交通工具将SQL命令推送到MySQL服务器上执行
            String sql = "insert into staffs(username,age,salary) values ('Martin',18,999.19),('Tom',58,999.19);";
    
            //5.执行插入SQL命令
            int counter = ps.executeUpdate(sql);
            System.out.println(counter);
    
            //6.关闭数据库连接资源
            if (conn != null) {
                conn.close();
            }
    
            if (ps != null) {
                ps.close();
            }
    
        }
    
    
    }

    3.更新记录

    import java.sql.Connection;
    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    
    public class update02 {
        public static void main(String[] args) throws Exception {
            //1.将MySQL服务器提供的jar包中的Driver接口实现类,注册到JVM中
    //        Driver driver = new com.mysql.jdbc.Driver();
    //        DriverManager.registerDriver(driver);
            Class.forName("com.mysql.jdbc.Driver");
    
            //2.通过DriverManager建立数据库连接通道
            String dbURL = "jdbc:mysql://192.168.0.98:3306/zhanggen?characterEncoding=utf8";
            Connection conn = DriverManager.getConnection(dbURL, "用户", "密码");
    
            //3.在通道上创建1个运输SQL的交通工具.
            PreparedStatement ps = conn.prepareStatement("");
    
            //4.使用交通工具运输SQL;
            String sql = "update staffs set age=18 where username='Martin';";
            int couner = ps.executeUpdate(sql);
            System.out.printf("更新了%s条数据\n", couner);
    
            //5.回收数据库资源
            if (conn != null) {
                conn.close();
            }
    
            if (ps != null) {
                ps.close();
            }
    
    
        }
    }

    4.查询

    以上我们使用statement对象的executeUpdate()方法对数据库进行了增、删、该操作。

    使用statement对象的executeQuery()方法可以进行数据库的查询。

    executeQuery()方法执行之后,查询结果会保存在ResultSet对象中。

    JDBC查询结果的获取顺序:先向下移动一行,锁定当前行之后,逐个获取当前行的列。

    ResultSet.next():游标向下移动一行,

    Result.getString(参数):获取当前行的某1列

    package com.mingde;
    
    import java.sql.*;
    
    public class JdbcDemo3 {
        public static void main(String[] args) {
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String dbURL = "jdbc:mysql://192.168.0.98:3306/zhanggen?characterEncoding=utf8";
                connection = DriverManager.getConnection(dbURL, "weike", "weike@123");
                statement = connection.createStatement();
                String QuerySQL = "select id,username,age,salary from staffs";
                //executeQuery:JDBC查询API
                resultSet = statement.executeQuery(QuerySQL);
                //游标向下锁定一行
                //boolean next = resultSet.next();
                while (resultSet.next()) {
                    //获取当前行的每个列
                    int id = resultSet.getInt("id");
                    String userName = resultSet.getString("username");
                    int age = resultSet.getInt("age");
                    double salary = resultSet.getDouble("salary");
                    System.out.println(id + "----" + "----" + userName + "----" + age + "--------" + salary);
                }
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (resultSet != null) {
                        resultSet.close();
                    }
                    if (statement != null) {
                        statement.close();
                    }
                    if (connection != null) {
                        connection.close();
                    }
                    
                } catch (SQLException e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    } 

    5.查询结果封装到List集合中

    package com.mingde;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    public class JdbcDemo4 {
        public static void main(String[] args) {
            List allStaffs = findAll();
            System.out.println(allStaffs.size());
            System.out.println(allStaffs);
    
        }
    
        //封装查询所有记录方法
        private static List findAll() {
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
            List<Staff> staffList = new ArrayList<Staff>();
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String dbURL = "jdbc:mysql://192.168.0.98:3306/zhanggen?characterEncoding=utf8";
                connection = DriverManager.getConnection(dbURL, "weike", "weike@123");
                statement = connection.createStatement();
                String QuerySQL = "select id,username,age,salary from staffs";
                resultSet = statement.executeQuery(QuerySQL);
                while (resultSet.next()) {
                    //创建Staff对象并给属性赋值
                    Staff staff = new Staff();
                    staff.setId(resultSet.getInt("id"));
                    staff.setUsername(resultSet.getString("username"));
                    staff.setAge(resultSet.getInt("age"));
                    staff.setSalary(resultSet.getDouble("salary"));
                    //Staff对象装载到list中
                    staffList.add(staff);
                }
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (resultSet != null) {
                        resultSet.close();
                    }
                    if (statement != null) {
                        statement.close();
                    }
                    if (connection != null) {
                        connection.close();
                    }
    
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return staffList;
        }
    }
    jdbc查询所有记录封装

    6.查询封装为工具类

    package util;
    
    import java.io.FileReader;
    import java.io.IOException;
    import java.sql.*;
    import java.util.Properties;
    
    public class JDBCUtils {
        //使用静态代码块,加载类时,读取一次配置文件
        private static String dbURL;
        private static String user;
        private static String password;
        private static String driver;
    
        static {
            try {
                //加载配置文件
                Properties properties = new Properties();
                //获取src/main/resources的路径/jdbc.properties
                String configFilePath =JDBCUtils.class.getClassLoader().getResource("jdbc.properties").getPath();
                properties.load(new FileReader(configFilePath));
                dbURL = properties.getProperty("url");
                user = properties.getProperty("user");
                password = properties.getProperty("password");
                //注册驱动
                driver = properties.getProperty("driver");
                Class.forName(driver);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        //获取连接,返回连接对象
        public static Connection getConnection() {
            Connection connection = null;
            try {
                connection = DriverManager.getConnection(dbURL, user, password);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return connection;
        }
    
        //释放数据库资源
        public static void close(Statement statement, Connection connection) {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
        //重写释放数据库资源
        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();
                }
            }
        }
    }
    JDBCUtils

    7.SQL预编译和批量执行

    SQL预编译可以防止SQL注入,批量执行可以提升SQL执行的效率;

    我们通过set数据类型,给PrepareStatement对象的占位符赋值。

    package com.mingde;
    
    import java.sql.*;
    
    public class JdbcDemo6 {
        public static void main(String[] args) {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String dbURL = "jdbc:mysql://192.168.0.98:3306/zhanggen?characterEncoding=utf8";
                connection = DriverManager.getConnection(dbURL, "weike", "weike@123");
                //1.定义带?占位符的SQL语句
                String preparedSQL = "select id,username,age,salary from staffs where username=? and age=?";
                //2.把带?占位符的SQL语句先传输到MySQL Server
                preparedStatement = connection.prepareStatement(preparedSQL);
                //3.给第1个? 赋值
                preparedStatement.setString(1, "Martin");
                //4.给第2个? 赋值
                preparedStatement.setInt(2, 18);
                //5.再把参数传输到MySQL Server,
                //6.然后再进行SQL语句和参数的替换
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()) {
                    //获取当前行的每个列
                    int id = resultSet.getInt("id");
                    String userName = resultSet.getString("username");
                    int age = resultSet.getInt("age");
                    double salary = resultSet.getDouble("salary");
                    System.out.println(id + "----" + "----" + userName + "----" + age + "--------" + salary);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (resultSet != null) {
                        resultSet.close();
                    }
                    if (preparedStatement != null) {
                        preparedStatement.close();
                    }
                    if (connection != null) {
                        connection.close();
                    }
    
                } catch (SQLException e) {
                    e.printStackTrace();
                }
    
            }
        }
    }

    8.jdbc控制事务

    事务:1组包含多个步骤的数据库操作。如果这组业务被事务管理,则这多个步骤要么一起成功,要么一起失败。

    事务包含3个操作:开始事务、提交事务 或者 回归事务。

    connection.setAutoCommit(false):开启事务
    commit():事务
    提交/执行
    rollback:事务回滚
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class Transaction05 {
        //jdbc的事务操作
        public static void main(String[] args) throws Exception {
            //1.注册MySQL driver
            Class.forName("com.mysql.jdbc.Driver");
            //2.创建数据库连接
            String dbURL = "jdbc:mysql://192.168.0.98:3306/zhanggen?characterEncoding=utf8";
            Connection conn = DriverManager.getConnection(dbURL, "用户", "密码");
            //3.命令启动事务相当于执行start transaction;
            conn.setAutoCommit(false);
            PreparedStatement ps = conn.prepareStatement("");
            String sql1 = "delete from staffs where username='张根85';";
            String sql2 = "delete from staffs where username='张根86';";
    
            try {
                int count1 = ps.executeUpdate(sql1);
                int count2 = ps.executeUpdate(sql2);
                System.out.println(count1);
                System.out.println(count2);
                conn.commit();
            } catch (SQLException e) {
                //SQL执行出现异常回滚
                System.out.println("回滚了!");
                conn.rollback();
            } finally {
                if (ps != null) {
                    ps.close();
                }
                if (conn != null) {
                    conn.close();
                }
    
            }
    
    
        }
    }

    三、数据库连接池

    在业务比较繁忙的情况下,客户端频繁发起系统调用创建数据库连接然后再关闭连接,浪费客户端系统资源,也比较耗时。

    在Java中可以使用c3p0和阿里开发的druid 第三方包创建1个数据库连接池。

    其中c3p0会自动去加载配置文件,而druid使用工厂类获取数据库连接对象。

    1.c3p0创建数据库连接池

    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
        <!--new ComboPooledDataSource("mvcApp");使用 -->
        <named-config name="mvcApp">
            <property name="user">weike</property>
            <property name="password">weike@123</property>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="jdbcUrl">jdbc:mysql://192.168.0.98:3306/zhanggen?useUnicode=true&amp;serverTimezone=UTC&amp;characterEncoding=UTF-8</property>
            <!-- 以上的user是数据库的用户,
             password是数据库的密码,driverClass是mysql的数据库驱动,
             jdbcUrl是连接数据库的url -->
            <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->
            <property name="acquireIncrement">5</property>
            <!--初始化时获取十个连接,取值应在minPoolSize与maxPoolSize之间 -->
            <property name="initialPoolSize">10</property>
            <!--连接池中保留的最小连接数 -->
            <property name="minPoolSize">10</property>
            <!--连接池中保留的最大连接数-->
            <property name="maxPoolSize">10</property>
            <!--超时时间为3秒-->
            <property name="checkoutTimeout">3000</property>
            <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
            <property name="maxStatements">20</property>
            <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
            <property name="maxStatementsPerConnection">5</property>
        </named-config>
    </c3p0-config>
    c3p0-config.xml

    -----------------

    package com.mingde.c3p0;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    
    public class C3P0Demo1 {
        public static void main(String[] args) throws Exception {
            //1.创建数据库连接池对象,指定数据库配置mvcApp
            DataSource dataSource = new ComboPooledDataSource("mvcApp");
            //2.从连接池中获取连接对象
            for (int i = 0; i <= 10; i++) {
                Connection connection = dataSource.getConnection();
                System.out.println(connection);
            }
    
    
        }
    }
    C3P0Demo1.java

    2.druid创建数据库连接池

    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://192.168.0.98:3306/zhanggen?serverTimezone=PRC
    username=weike
    password=weike@123
    #初始化连接数
    initialSize=10
    minIdle=5
    #最大连接数
    maxActive=10
    #最大等待时间
    maxWait=3000
    
    timeBetweenEvictionRunsMillis=6000
    minEvictableIdleTimeMillis=300000
    testWhileIdle=true
    testOnBorrow=true
    testOnReturn=true
    poolPreparedStatements=true
    maxPoolPreparedStatementPerConnectionSize=20
    validationQuery=select 1
    filters=stat
    druid.properties

    ----------------------

    package com.mingde.druid;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.util.Properties;
    
    public class DruidDemo1 {
        public static void main(String[] args)throws Exception {
            //加载配置文件
            Properties properties=new Properties();
            InputStream resourceAsStream = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
            properties.load(resourceAsStream);
            //创建连接池
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            //通过工厂类获取连接对象
            for (int i = 0; i <11 ; i++) {
                Connection connection = dataSource.getConnection();
                System.out.println(connection);
            }
    
    
    
    
    
        }
    }
    DruidDemo1.java

    3. druid工具类

    package util;
    
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.IOException;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    
    public class DruidUtils {
        //1.定义成员变量
        private static DataSource dataSource;
    
        static {
            try {
                //2.加载配置文件
                Properties properties = new Properties();
                properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
                //3.创建Druid连接池
                dataSource = DruidDataSourceFactory.createDataSource(properties);
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
        //获取数据库连接方法
        public static Connection getConnection() {
            Connection connection = null;
            try {
                connection = dataSource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return connection;
        }
    
        //释放数据库连接资源方法 DML
        public static void Close(Statement statement, Connection connection) {
            try {
                if (statement != null) {
                    //归还数据库连接到数据库连接池
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        //释放数据库连接资源方法 DDL
        public static void Close(ResultSet resultSet, Statement statement, Connection connection) {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    //归还数据库连接到数据库连接池
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        //获取连接池
        public static DataSource getDataSource() {
            return dataSource;
        }
    }
    DruidUtils.java

    4.使用Junit包对druid工具类进行单元测试

    Junit单元测试,可以让类中的方法 在不依赖main方法的情况下独立执行。

    package com.mingde;
    
    
    import org.junit.Test;
    import util.DruidUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    public class TestUtilsDemo {
        @Test
        public void testInsert() throws Exception {
            //1.获取连接
            Connection connection = DruidUtils.getConnection();
            //2.定义SQL
            String insertSql = "insert into staffs (username,age,salary)  values (?,?,?)";
            //3.获取statement对象
            PreparedStatement preparedStatement = connection.prepareStatement(insertSql);
            //4.给?占位符赋值
            preparedStatement.setString(1, "卢俊义");
            preparedStatement.setInt(2, 68);
            preparedStatement.setDouble(3, 56.9);
            int count = preparedStatement.executeUpdate();
            System.out.println(count);
            //5.关闭数据库连接资源
            DruidUtils.Close(preparedStatement, connection);
        }
    
        @Test
        public void testQuery() throws Exception {
            //1.获取连接
            Connection connection = DruidUtils.getConnection();
            //2.定义SQL
            String querySql = "select id,username,age,salary from staffs where id = ?";
            //3.获取statement对象
            PreparedStatement preparedStatement = connection.prepareStatement(querySql);
            //4.把?占位符 赋值为45
            preparedStatement.setInt(1, 45);
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                //获取当前行的每个列
                int id = resultSet.getInt("id");
                String userName = resultSet.getString("username");
                int age = resultSet.getInt("age");
                double salary = resultSet.getDouble("salary");
                System.out.println(id + "----" + "----" + userName + "----" + age + "--------" + salary);
            }
            //5.关闭数据库连接资源
            DruidUtils.Close(resultSet, preparedStatement, connection);
        }
    
    }
    TestUtilsDemo.java

    5.使用druid之后产生大量超时连接

    mysql> show processlist;
    +------+-------+------------------+--------------+---------+-------+----------+------------------+
    | Id   | User  | Host             | db           | Command | Time  | State    | Info             |
    +------+-------+------------------+--------------+---------+-------+----------+------------------+
    |  473 | root  | 172.17.0.1:54128 | db_gjdw_eova | Sleep   |     1 |          | NULL             |
    |  604 | root  | 172.17.0.1:54420 | db_gjdw_eova | Sleep   |   912 |          | NULL             |
    |  606 | root  | 172.17.0.1:54424 | db_gjdw_data | Sleep   |   915 |          | NULL             |
    |  634 | root  | 172.17.0.1:54480 | db_gjdw_eova | Sleep   |   912 |          | NULL             |
    |  635 | root  | 172.17.0.1:54482 | db_gjdw_data | Sleep   |   596 |          | NULL             |
    |  636 | weike | 172.17.0.1:54484 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  637 | weike | 172.17.0.1:54486 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  638 | weike | 172.17.0.1:54488 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  639 | weike | 172.17.0.1:54490 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  640 | weike | 172.17.0.1:54492 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  641 | weike | 172.17.0.1:54494 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  642 | weike | 172.17.0.1:54496 | db_hbdw_data | Sleep   |  9278 |          | NULL             |
    |  643 | weike | 172.17.0.1:54498 | db_hbdw_data | Sleep   |  9276 |          | NULL             |
    |  644 | weike | 172.17.0.1:54500 | db_hbdw_data | Sleep   | 10605 |          | NULL             |
    |  645 | weike | 172.17.0.1:54502 | db_hbdw_data | Sleep   |   722 |          | NULL             |
    |  646 | weike | 172.17.0.1:54504 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  647 | weike | 172.17.0.1:54506 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  648 | weike | 172.17.0.1:54508 | db_hbdw_data | Sleep   | 20533 |          | NULL             |
    |  649 | weike | 172.17.0.1:54510 | db_hbdw_data | Sleep   |  3559 |          | NULL             |
    |  650 | weike | 172.17.0.1:54512 | db_hbdw_data | Sleep   |  4831 |          | NULL             |
    |  651 | weike | 172.17.0.1:54514 | db_hbdw_data | Sleep   | 20144 |          | NULL             |
    |  652 | weike | 172.17.0.1:54516 | db_hbdw_data | Sleep   |    67 |          | NULL             |
    |  653 | weike | 172.17.0.1:54518 | db_hbdw_data | Sleep   |    67 |          | NULL             |
    |  654 | weike | 172.17.0.1:54520 | db_hbdw_data | Sleep   | 20144 |          | NULL             |
    |  655 | weike | 172.17.0.1:54522 | db_hbdw_data | Sleep   |  5224 |          | NULL             |
    |  700 | weike | 172.17.0.1:54700 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  701 | weike | 172.17.0.1:54704 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  702 | weike | 172.17.0.1:54708 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  703 | weike | 172.17.0.1:54712 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  704 | weike | 172.17.0.1:54716 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  705 | weike | 172.17.0.1:54720 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  706 | weike | 172.17.0.1:54724 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  707 | weike | 172.17.0.1:54728 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  708 | weike | 172.17.0.1:54732 | rmyh         | Sleep   |  3502 |          | NULL             |
    |  709 | weike | 172.17.0.1:54736 | rmyh         | Sleep   |  3502 |          | NULL             |
    |  710 | weike | 172.17.0.1:54740 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  711 | weike | 172.17.0.1:54744 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  712 | weike | 172.17.0.1:54748 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  713 | weike | 172.17.0.1:54752 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  714 | weike | 172.17.0.1:54756 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  715 | weike | 172.17.0.1:54760 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  716 | weike | 172.17.0.1:54764 | rmyh         | Sleep   |  7666 |          | NULL             |
    |  717 | weike | 172.17.0.1:54768 | rmyh         | Sleep   |  7666 |          | NULL             |
    |  718 | weike | 172.17.0.1:54772 | rmyh         | Sleep   |  3502 |          | NULL             |
    |  719 | weike | 172.17.0.1:54776 | rmyh         | Sleep   |  3481 |          | NULL             |
    |  720 | weike | 172.17.0.1:54780 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  721 | weike | 172.17.0.1:54784 | rmyh         | Sleep   |  9553 |          | NULL             |
    |  722 | weike | 172.17.0.1:54788 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  723 | weike | 172.17.0.1:54792 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  724 | weike | 172.17.0.1:54796 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  725 | weike | 172.17.0.1:54800 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  726 | weike | 172.17.0.1:54804 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  727 | weike | 172.17.0.1:54808 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  728 | weike | 172.17.0.1:54812 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  729 | weike | 172.17.0.1:54816 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  730 | weike | 172.17.0.1:54820 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  731 | weike | 172.17.0.1:54824 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  732 | weike | 172.17.0.1:54828 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  733 | weike | 172.17.0.1:54832 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  734 | weike | 172.17.0.1:54836 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  735 | weike | 172.17.0.1:54840 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  736 | weike | 172.17.0.1:54844 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  737 | weike | 172.17.0.1:54848 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  738 | weike | 172.17.0.1:54852 | rmyh         | Sleep   |  9552 |          | NULL             |
    |  739 | weike | 172.17.0.1:54856 | rmyh         | Sleep   |  9552 |          | NULL             |
    | 1016 | root  | 172.17.0.1:55408 | db_gjdw_data | Sleep   |   917 |          | NULL             |
    | 1017 | root  | 172.17.0.1:55410 | db_gjdw_data | Sleep   |   911 |          | NULL             |
    | 1018 | root  | 172.17.0.1:55412 | db_gjdw_data | Sleep   |   911 |          | NULL             |
    | 1019 | root  | 172.17.0.1:55414 | db_gjdw_eova | Sleep   |   911 |          | NULL             |
    | 1043 | root  | 172.17.0.1:55462 | db_gjdw_eova | Sleep   |   912 |          | NULL             |
    | 1044 | root  | 172.17.0.1:55464 | db_gjdw_data | Sleep   |   911 |          | NULL             |
    | 1045 | root  | 172.17.0.1:55466 | db_gjdw_eova | Sleep   |   911 |          | NULL             |
    | 1046 | root  | 172.17.0.1:55468 | db_gjdw_data | Sleep   |   917 |          | NULL             |
    | 1047 | root  | 172.17.0.1:55470 | db_gjdw_data | Sleep   |   911 |          | NULL             |
    | 1048 | root  | 172.17.0.1:55472 | db_gjdw_data | Sleep   |   911 |          | NULL             |
    | 1055 | weike | 172.17.0.1:55486 | zhanggen     | Sleep   |   765 |          | NULL             |
    | 1056 | weike | 172.17.0.1:55488 | zhanggen     | Sleep   |   765 |          | NULL             |
    | 1088 | root  | localhost        | NULL         | Query   |     0 | starting | show processlist |
    +------+-------+------------------+--------------+---------+-------+----------+------------------+
    78 rows in set (0.00 sec)
    mysql> show processlist;

    我修改了数据库配置文件在MySQL server端对连接超时时间进行了限制。

    [mysqld]
    user=mysql
    character-set-server=utf8
    skip-name-resolve
    #连接超时时间
    wait_timeout=10
    #普通SQL执行日志 
    general_log=ON
    general_log_file=/var/log/docker/query.log 
    #慢日志执行日志
    slow_query_log=ON 
    slow_query_log=5 
    slow_query_log_file=/var/log/docker/slow-query.log
    default_authentication_plugin=mysql_native_password
    sql_mode =STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    [client]
    default-character-set=utf8
    [mysql]
    default-character-set=utf8
    my.cnf

    四、JdbcTemplate

    JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。

    jdbc Template是建立在1个数据库连接池之上的。

    JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果。

    1.JdbcTemplate 快速入门

    package com.zhanggen;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    import util.DruidUtils;
    import util.JDBCUtils;
    
    public class jdbcTemplateDemo1 {
        public static void main(String[] args) {
            //1.创建JDBCTemplate对象,需要1个依赖1个数据库连接池 参数
            JdbcTemplate template=new JdbcTemplate(DruidUtils.getDataSource());
            //2.调用方法
            String sql="update staffs set username = ? where id = ?";
            int count = template.update(sql, "武松", 46);
            System.out.println(count);
    
        }
    }

    2.JdbcTemplate 执行DML语句

     使用Jdbc Template执行增、删、修改操作。

    package com.zhanggen;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.jdbc.core.JdbcTemplate;
    import util.DruidUtils;
    
    public class JdbcTemplateDemo2 {
    
        private static JdbcTemplate template = new JdbcTemplate(DruidUtils.getDataSource());
        private static String preparedSQL = null;
    
        public static void indertEntry() throws Exception {
            preparedSQL = "update (taffs set age=? where username=?";
            template.update(preparedSQL, 89, "武松");
        }
    
        public static void addStaff() {
            preparedSQL = "insert into staffs (username,age,salary) values (?,?,?)";
            template.update(preparedSQL, "张无忌", 30, 98.98);
        }
    
        public static void deleteStaff() {
            preparedSQL = "delete from staffs where username=?";
            template.update(preparedSQL, "藤田刚");
        }
    
    }

    2.JdbcTemplate 执行DQL语句

    使用Jdbc Template执行数据库查询操作,并把查询结果封装成对象,添加到List中。

    package com.zhanggen;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowMapper;
    import util.DruidUtils;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.List;
    import java.util.Map;
    
    public class JdbcTemplateDemo2 {
    
        private static JdbcTemplate template = new JdbcTemplate(DruidUtils.getDataSource());
        private static String preparedSQL = null;
    
        //1.JdbcTemplate执行DML操作
        public static void indertEntry() throws Exception {
            preparedSQL = "update (taffs set age=? where username=?";
            template.update(preparedSQL, 89, "武松");
        }
    
        public static void addStaff() {
            preparedSQL = "insert into staffs (username,age,salary) values (?,?,?)";
            template.update(preparedSQL, "张无忌", 30, 98.98);
        }
    
        public static void deleteStaff() {
            preparedSQL = "delete from staffs where username=?";
            template.update(preparedSQL, "藤田刚");
        }
    
        //2.JdbcTemplate执行DQL操作
        public static void queryForMap() {
            //查询结果封装为map类型
            preparedSQL = "select username,age,salary from staffs where id = ?";
            Map<String, Object> map = template.queryForMap(preparedSQL, 44);
            System.out.println(map);
    
        }
    
        public static void queryForList() {
            //查询结果封装为List类型
            preparedSQL = "select * from staffs";
            List<Map<String, Object>> list = template.queryForList(preparedSQL);
            System.out.println(list);
    
        }
    
        public static void query1() {
            //查询staffs表中所有记录,把每一条记录封装为staff对象,并添加到集合中。
            preparedSQL = "select * from staffs";
            List<Staff> staffList = template.query(preparedSQL, new RowMapper<Staff>() {
                @Override
                public Staff mapRow(ResultSet resultSet, int i) throws SQLException {
                    Staff staff = new Staff();
                    int id = resultSet.getInt("id");
                    String username = resultSet.getString("username");
                    int age = resultSet.getInt("age");
                    double salary = resultSet.getDouble("salary");
                    staff.setId(id);
                    staff.setUsername(username);
                    staff.setAge(age);
                    staff.setSalary(salary);
                    return staff;
                }
            });
            System.out.println(staffList);
        }
    
        public static void query2() {
            //简化版
            //查询staffs表中所有记录,把每一条记录自动封装为staff对象,并添加到集合中。
            preparedSQL = "select * from staffs";
            List<Staff> staffList = template.query(preparedSQL, new BeanPropertyRowMapper<Staff>(Staff.class));
            System.out.println(staffList);
        }
    
        //3.用于做SQL聚合函数的查询
        public static void queryForObject() {
            preparedSQL = "select count(id) from staffs";
            Long total = template.queryForObject(preparedSQL, Long.class);
            System.out.println(total);
        }
    
    
    }

     

    五、DAO层概念

    ORM可以帮助我们把数据中表映射为class类,把每表中的每条记录映射为object对象,使我们可以通过代码操作数据库,在这个基础之上我们还可以进一步对操作数据库的代码进行封装,那就是使用DAO层。

    在Java中我们可以使用DAO类对JDB操作表的细节进行代码封装;

    DAO(Database Access Object)是指可以提供数据库访问对象的类

    作用:数据库访问对象(DAO)在开发时提供针对某1张表的增删改查操作细节;

    优势:DAO可以提高代码封装性,通过数据库访问对象可以避免反复书写SQL以及JDBC开发步骤的书写;

    开发规则:

    1个DAO类中封装1张表的封装细节;

    DAO类命名规则:表名+Dao,比如对employee表的增删改查操作细节进行封装,此时的DAO就应该命名为EmployeeDAO;

    DAO类所在包的命名规则:公司网站的域名.dao,例如com.le.dao;

    参考

  • 相关阅读:
    WEB 应用缓存解析以及使用 Redis 实现分布式缓存
    MVC 架构模式
    用两个栈实现队列
    重建二叉树
    从尾到头打印链表
    替换空格
    二维数组中的查找
    二叉树与线索二叉树
    OpenYurt:延伸原生 Kubernetes 到边缘场景下的落地实践
    开放下载!解锁 Serverless 从入门到实战大“橙”就
  • 原文地址:https://www.cnblogs.com/sss4/p/15641832.html
Copyright © 2020-2023  润新知