前言
在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> <!--<!– FIXME change it to the project's website –>--> <!--<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>
一、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; } }
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(); } } } }
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&serverTimezone=UTC&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>
-----------------
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); } } }
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
----------------------
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); } } }
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; } }
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); } }
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 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
四、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;