JDBC-万字长文总结

  • 1. 概述
    • 1.1 什么是JDBC
    • 1.2 JDBC API
    • 1.3 JDBC 可以做什么
    • 1.4 JDBC程序编写步骤
  • 2. 演示完整步骤
    • 2.1 引入JDBC驱动程序
    • 2.2 加载并注册驱动
      • 2.2.1 Class.forName( )
      • 2.2.2 服务提供者框架
    • 2.3 获取数据库链接
    • 2.4 操作或访问数据库
      • 2.4.1 Statement
      • 2.4.2 ResultSet
    • 2.5 释放资源
  • 3. 封装JDBCUtils
  • 4. PreparedStatement
    • 4.1 Statement的不足
    • 4.2 PreparedStatement概述
    • 4.3 PreparedStatement vs Statement
    • 4.4 JDBC 取得数据库自动生成的主键
  • 5. 事务
  • 6. 批处理
  • 7. Blob类型数据的读写
  • 8. 数据库连接池
    • 8.1 数据库连接池
  • 9. Apache—DBUtils简介
    • 9.1 DbUtils类
    • 9.2 QueryRunner类
  • 10. DAO和增删改查通用方法
    • 10.1 DAO接口
    • 10.2 BasicDAOImpl
    • 10.3 DAO实现类

1. 概述

在Java中,数据库存取技术可分为如下几类:

  • JDBC直接访问数据库
  • JDO技术(Java Data Object)
  • 第三方O/R工具,如Hibernate, Mybatis 等

JDBC是java访问数据库的基石,JDO, Hibernate等只是更好的封装了JDBC。

1.1 什么是JDBC

JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统(DBMS)、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,使用这个类库可以以一种标准的方法、方便地访问数据库资源。

JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。

JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

如果没有JDBC,那么Java程序访问数据库时是这样的:


JDBC是SUN公司提供一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可。

不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。

1.2 JDBC API

JDBC API是一系列的接口,它统一和规范了应用程序与数据库的连接、执行SQL语句,并到得到返回结果等各类操作。声明在java.sql与javax.sql包中。

1.3 JDBC 可以做什么


我们可以做以下事情:增删改查

①查询女神们的基本信息
②查询女神们的详细信息
③查询心仪女神的电话号码 ,噢耶
④添加心仪的女神
⑤删除不符合要求的女神
⑥修改女神的信息
⑦查询管理员的所有信息

1.4 JDBC程序编写步骤

  1. 注册驱动
  2. 获取连接
  3. 执行增删改查
  4. 释放资源

2. 演示完整步骤

2.1 引入JDBC驱动程序

准备工作:引入JDBC驱动程序

驱动程序由数据库提供商提供下载。 MySQL的驱动下载地址:http://dev.mysql.com/downloads/

如何在Java Project项目应用中添加数据库驱动jar:


1.把上图.jar包拷贝到项目中一个目录中:

2.添加到项目的类路径下

在驱动jar上右键–>Build Path-->Add to Build Path

注意:如果是Dynamic Web Project(动态的web项目)话,则是把驱动jar放到WebContent(有的开发工具叫WebRoot)目录中的WEB-INF目录中的lib目录下即可

2.2 加载并注册驱动

加载并注册驱动:
加载驱动,把驱动类加载到内存
注册驱动,把驱动类的对象交给DriverManager管理,用于后面创建连接等使用。

2.2.1 Class.forName( )

因为 Driver 接口的驱动程序类都包含了静态代码块,在这个静态代码块中,会调用 DriverManager.registerDriver() 方法来注册自身的一个实例,所以可以换一种方式来加载驱动。(即只要想办法让驱动类的这段静态代码块执行即可注册驱动类,而要让这段静态代码块执行,只要让该类被类加载器加载即可)

调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名:

//通过反射,加载与注册驱动类,解耦合(不直接依赖)
Class.forName("com.mysql.jdbc.Driver");

2.2.2 服务提供者框架

服务提供者框架(例如:JDBC的驱动程序)自动注册(有版本要求)

符合JDBC 4.0规范的驱动程序包含了一个文件META-INF/services/java.sql.Driver,在这个文件中提供了JDBC驱动实现的类名。

例如:mysql-connector-java-5.1.40-bin.jar文件中就可以找到java.sql.Driver文件,用文本编辑器打开文件就可以看到:com.mysql.jdbc.Driver类。

JVM的服务提供者框架在启动应用时就会注册服务,例如:MySQL的JDBC驱动就会被注册,而原代码中的Class.forName("com.mysql.jdbc.Driver")仍然可以存在,但是不会起作用。

但是注意mysql-connector-java-5.0.8-bin.jar版本的jar中没有,如下:

2.3 获取数据库链接

可以通过 DriverManager 类建立到数据库的连接Connection

DriverManager 试图从已注册的 JDBC 驱动程序集中选择一个适当的驱动程序。

  • public static Connection getConnection(String url)
  • public static Connection getConnection(String url,String user, String password)
  • public static Connection getConnection(String url,Properties info)其中Properties info通常至少应该包括 “user” 和 “password” 属性

JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。JDBC URL的标准由三部分组成,各部分间用冒号分隔。 jdbc:<子协议>:<子名称>

  • 协议:JDBC URL中的协议总是jdbc
  • 子协议:子协议用于标识一个数据库驱动程序
  • 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息

例如:

MySQL的连接URL编写方式:

  • jdbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=值&参数=值
  • jdbc:mysql://localhost:3306/testdb
  • jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf8(如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
  • jdbc:mysql://localhost:3306/testdb?user=root&password=123456
//1、加载与注册驱动
Class.forName("com.mysql.jdbc.Driver");//2、获取数据库连接
String url = "jdbc:mysql://localhost:3306/test";
Connection conn = DriverManager.getConnection(url, "root", "root");

2.4 操作或访问数据库

数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。

其实一个数据库连接就是一个Socket连接。

在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:

  • Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
  • PrepatedStatement :SQL语句被预编译并存储在此对象中,然后可以使用此对象多次高效地执行该语句。
  • CallableStatement:用于执行 SQL 存储过程

2.4.1 Statement

通过调用 Connection 对象的 createStatement() 方法创建该对象

该对象用于执行静态的 SQL 语句,并且返回执行结果

Statement 接口中定义了下列方法用于执行 SQL 语句:

  • int excuteUpdate(String sql):执行更新操作INSERT、UPDATE、DELETE
  • ResultSet excuteQuery(String sql):执行查询操作SELECT

2.4.2 ResultSet

通过调用 Statement 对象的 excuteQuery() 方法创建该对象

ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商实现

ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行

ResultSet 接口的常用方法:

boolean next()
getXxx(String columnLabel):columnLabel使用 SQL AS 子句指定的列标签。如果未指定 SQL AS 子句,则标签是列名称
getXxx(int index) :索引从1开始

增删改查示例代码:

public class TestConnection {//增删改@Testpublic void testUpdate() throws  Exception {//步骤1:注册驱动(为了让mysql的实现类加载到内存可以使用)//     DriverManager.registerDriver(new Driver());Class.forName("com.mysql.jdbc.Driver");//步骤2:获取连接Properties properties  = new Properties();//配置文件要求里面必须有连接参数和配置参数properties.load(new FileInputStream("src\\druid.properties"));DataSource ds =  DruidDataSourceFactory.createDataSource(properties);Connection connection = ds.getConnection();//步骤3:执行增删改查操作//①获取执行sql语句的命令对象Statement statement = connection.createStatement();//②执行sql语句
//      statement.executeQuery(sql);//执行查询语句
//      statement.executeUpdate(sql)//执行增删改语法,返回受影响行数
//      statement.execute(sql)//执行任何sql语句int update = statement.executeUpdate("delete from admin where id =1");//③处理结果System.out.println(update>0?"成功":"失败");//步骤4:关闭连接(释放资源)statement.close();connection.close();}//查询@Test public void testQuery() throws Exception {//1.注册驱动Class.forName("com.mysql.jdbc.Driver");       //2.获取连接Properties  pro = new Properties();pro.load(new FileInputStream("src\\druid.properties"));DataSource ds = DruidDataSourceFactory.createDataSource(pro);Connection connection = ds.getConnection();//3.执行查询//①获取执行sql的命令对象Statement statement = connection.createStatement();//②执行sqlResultSet set = statement.executeQuery("select name bname,sex gender,borndate born from beauty");while(set.next()) {String name = set.getString("bname");char gender = set.getString("gender").charAt(0);Date date = set.getDate("born");//       String date = set.getString("born");System.out.println(name+"\t"+gender+"\t"+date);}//4.关闭set.close();statement.close();connection.close();}
}

2.5 释放资源

Connection、Statement、ResultSet都是应用程序和数据库服务器的连接资源,使用后一定要关闭,可以在finally中关闭

演示未关闭后果:

package com.atguigu.conn;import java.sql.Connection;
import java.sql.DriverManager;public class TestConnectionClose {public static void main(String[] args) throws Exception{//1、加载与注册驱动Class.forName("com.mysql.jdbc.Driver");//2、获取数据库连接String url = "jdbc:mysql://localhost:3306/test";//my.ini中max_connections=10for (int i = 0; i < 15; i++) {Connection conn = DriverManager.getConnection(url,"root", "123456");System.out.println(conn);//没有关闭,资源一直没有释放}}
}

3. 封装JDBCUtils

封装JDBCTools

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;import javax.sql.DataSource;import com.alibaba.druid.pool.DruidDataSourceFactory;/** 获取连接或释放连接的工具类*/
public class JDBCTools {// 1、数据源,即连接池private static DataSource dataSource;// 2、ThreadLocal对象private static ThreadLocal<Connection> threadLocal;static {try {//1、读取druip.properties文件Properties pro = new Properties();pro.load(JDBCTools.class.getClassLoader().getResourceAsStream("druid.properties"));//2、连接连接池dataSource = DruidDataSourceFactory.createDataSource(pro);//3、创建线程池threadLocal = new ThreadLocal<>();} catch (Exception e) {e.printStackTrace();}}/*** 获取连接的方法* * @return* @throws SQLException*/public static Connection getConnection() {// 从当前线程中获取连接Connection connection = threadLocal.get();if (connection == null) {// 从连接池中获取一个连接try {connection = dataSource.getConnection();// 将连接与当前线程绑定threadLocal.set(connection);} catch (SQLException e) {e.printStackTrace();}}return connection;}/*** 释放连接的方法* * @param connection*/public static void releaseConnection() {// 获取当前线程中的连接Connection connection = threadLocal.get();if (connection != null) {try {connection.close();// 将已经关闭的连接从当前线程中移除threadLocal.remove();} catch (SQLException e) {e.printStackTrace();}}}
}

4. PreparedStatement

4.1 Statement的不足

(1)SQL拼接
(2)SQL注入
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的做法。对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement 取代 Statement 就可以了。
(3)处理Blob类型的数据
BLOB (binary large object),二进制大对象,BLOB常常是数据库中用来存储二进制文件的字段类型。
插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的。

MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)

如果还是报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数:
max_allowed_packet=16M注意:修改了my.ini文件,一定要重新启动服务

实际使用中根据需要存入的数据大小定义不同的BLOB类型。

需要注意的是:如果存储的文件过大,数据库的性能会下降。

4.2 PreparedStatement概述

可以通过调用 Connection 对象的 preparedStatement(String sql) 方法获取 PreparedStatement 对象

PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句

PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值

ResultSet executeQuery()执行查询,并返回该查询生成的 ResultSet 对象。

int executeUpdate():执行更新,包括增、删、该

4.3 PreparedStatement vs Statement

代码的可读性和可维护性. Statement的sql拼接是个难题。

PreparedStatement 可以防止 SQL 注入

PreparedStatement 可以处理Blob类型的数据

PreparedStatement 能最大可能提高性能:(Oracle和PostgreSQL8是这样,但是对于MySQL不一定比Statement高)

DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。

4.4 JDBC 取得数据库自动生成的主键

获取自增长的键值:

(1)在创建PreparedStatement对象时
原来:

PreparedStatement pst = conn.preparedStatement(sql);
现在:
PreparedStatement pst = conn.prepareStatement(orderInsert,Statement.RETURN_GENERATED_KEYS);

(2)原来执行更新
原来:

int len = pst.executeUpdate();  现在:
int len = pst.executeUpdate();
ResultSet rs = pst.getGeneratedKeys();
if(rs.next()){Object key = rs.getObject(第几列);//获取自增长的键值
}

5. 事务

JDBC程序中当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。

JDBC程序中为了让多个 SQL 语句作为一个事务执行:(重点)

调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务

在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务

在其中某个操作失败或出现异常时,调用 rollback(); 方法回滚事务

若此时 Connection 没有被关闭, 则需要恢复其自动提交状态 setAutoCommit(true);

注意:

如果多个操作,每个操作使用的是自己单独的连接,则无法保证事务。即同一个事务的多个操作必须在同一个连接下.

package com.atguigu.transaction;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class TestTransaction {public static void main(String[] args){Connection conn = null;try {//1、连接数据库Class.forName("com.mysql.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/test";String user = "root";String password = "123456";conn = DriverManager.getConnection(url, user, password);//设置手动提交conn.setAutoCommit(false);String sql1 = "update t_department set description = ? where did = ?";PreparedStatement pst1 = conn.prepareStatement(sql1);pst1.setObject(1, "挣大钱的");pst1.setObject(2, 4);int len1 = pst1.executeUpdate();System.out.println(len1>0?"更新部门信息成功":"更新部门信息失败");pst1.close();String sql2 = "update t_employee set salary = salary + ? where did = ?";PreparedStatement pst2 = conn.prepareStatement(sql2);pst2.setObject(1, 20000);pst2.setObject(2, 4);int len2 = pst2.executeUpdate();System.out.println(len2>0?"更新部门信息成功":"更新部门信息失败");pst2.close();conn.commit();}catch (Exception e) {try {if(conn!=null){conn.rollback();}} catch (SQLException e1) {e1.printStackTrace();}} finally{try {if(conn!=null){//恢复自动提交conn.setAutoCommit(true);//释放连接conn.close();}} catch (SQLException e) {e.printStackTrace();}}}
}

6. 批处理

当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。

JDBC的批量处理语句包括下面两个方法:

addBatch():添加需要批量处理的SQL语句或参数
executeBatch():执行批量处理语句;
clearBatch():清空批处理包的语句

通常我们会遇到两种批量执行SQL语句的情况:

多条SQL语句的批量处理;


一个SQL语句的批量传参;


注意

JDBC连接MySQL时,如果要使用批处理功能,请再url中加参数?rewriteBatchedStatements=true

PreparedStatement作批处理插入时使用values(使用value没有效果)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;import org.junit.Test;public class TestBatch {@Testpublic void noBatch()throws Exception{Class.forName("com.mysql.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/test";String user = "root";String password = "123456";Connection conn = DriverManager.getConnection(url, user, password);String sql = "INSERT INTO t_department(dname,description) VALUES(?,?)";PreparedStatement st = conn.prepareStatement(sql);for(int i=0; i<1000; i++){st.setString(1, "测试部门" + i);st.setString(2, "测试部门描述"  + i);st.executeUpdate();}st.close();conn.close();}@Testpublic void useBatch()throws Exception{Class.forName("com.mysql.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true";String user = "root";String password = "123456";Connection conn = DriverManager.getConnection(url, user, password);String sql = "INSERT INTO t_department(dname,description) VALUES(?,?)";PreparedStatement st = conn.prepareStatement(sql);for(int i=0; i<1000; i++){st.setString(1, "测试部门" + i);st.setString(2, "测试部门描述"  + i);st.addBatch();}st.executeBatch();st.close();conn.close();}
}

7. Blob类型数据的读写

MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。

MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)

实际使用中根据需要存入的数据大小定义不同的BLOB类型。
需要注意的是:如果存储的文件过大,数据库的性能会下降

8. 数据库连接池

8.1 数据库连接池

(1)数据库连接池的必要性

不使用数据库连接池存在的问题:

  • 普通的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection 加载到内存中,再验证IP地址,用户名和密码(得花费0.05s~1s的时间)。需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接。这样的方式将会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重复利用.若同时有几百人甚至几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃。
  • 对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将导致重启数据库。
  • 这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

为解决传统开发中的数据库连接问题,可以采用数据库连接池技术(connection pool)。

数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。

预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。


数据库连接池技术的优点:

  • 资源重用:

    • 由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
  • 更快的系统反应速度

    • 数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间
  • 新的资源分配手段

    • 对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源
  • 统一的连接管理,避免数据库连接泄露

    • 在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露

(2)多种开源的数据库连接池

JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口,该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现:

DBCP 是Apache提供的数据库连接池,速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持

C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以

Proxool 是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点

BoneCP 是一个开源组织提供的数据库连接池,速度快

Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不知道是否有BoneCP快

DataSource 通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把 DataSource 称为连接池
注意:

  • 数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。
  • 当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但conn.close()并没有关闭数据库的物理连接,它仅仅把数据库连接释放,归还给了数据库连接池。

9. Apache—DBUtils简介

commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。

9.1 DbUtils类

DbUtils :提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:

9.2 QueryRunner类

该类封装了SQL的执行,是线程安全的。

(1)可以实现增、删、改、查、批处理、
(2)考虑了事务处理需要共用Connection。
(3)该类最主要的就是简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。

QueryRunner类提供了两个构造方法:

QueryRunner():默认的构造方法
QueryRunner(DataSource ds):需要一个 javax.sql.DataSource 来作参数的构造方法。

10. DAO和增删改查通用方法

DAO:Data Access Object访问数据信息的类和接口,包括了对数据的CRUD(Create、Retrival、Update、Delete),而不包含任何业务相关的信息

作用:为了实现功能的模块化,更有利于代码的维护和升级。

10.1 DAO接口

package com.atguigu.dao;import java.util.List;import com.atguigu.bean.Book;public interface BookDAO {/*** 获取所有图书的方法* * @return*/public List<Book> getBooks();/*** 添加图书的方法* * @param book*/public void addBook(Book book);/*** 根据图书的id删除图书的方法* * @param bookId*/public void deleteBookById(String bookId);/*** 根据图书的id获取图书信息* * @param bookId* @return*/public Book getBookById(String bookId);/*** 更新图书信息的方法* * @param book*/public void updateBook(Book book);/*** 批量更新图书的库存和销量* * @param params*/public void batchUpdateSalesAndStock(Object[][] params);
}package com.atguigu.dao;import java.util.List;import com.atguigu.bean.Order;public interface OrderDAO {/*** 保存订单的方法* * @param order*/public void saveOrder(Order order);/*** 获取所用订单的方法* * @return*/public List<Order> getOrders();/*** 获取我的订单的方法* * @param userId* @return*/public List<Order> getMyOrders(int userId);/*** 更新订单的状态的方法,例如已发货、确认收货等* * @param orderId* @param state*/public void updateOrderState(String orderId, int state);
}package com.atguigu.dao;import java.util.List;import com.atguigu.bean.OrderItem;public interface OrderItemDAO {/*** 根据订单号获取对应的订单项* * @param orderId* @return*/public List<OrderItem> getOrderItemsByOrderId(String orderId);/*** 批量插入订单项的方法* * @param params*/public void batchInsertOrderItems(Object[][] params);
}

10.2 BasicDAOImpl

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;import com.atguigu.util.JDBCTools;/*** 定义一个用来被继承的对数据库进行基本操作的Dao*/
public class BasicDAOImpl {private QueryRunner queryRunner = new QueryRunner();/*** 通用的增删改操作* * @param sql* @param params* @return*/public int update(String sql, Object... params) {// 获取连接Connection connection = JDBCTools.getConnection();int count = 0;try {count = queryRunner.update(connection, sql, params);} catch (SQLException e) {//将编译时异常转换为运行时异常向上抛throw new RuntimeException(e);}return count;}/*** 获取一个对象* * @param sql* @param params* @return*/public <T> T getBean(Class<T> type,String sql, Object... params) {// 获取连接Connection connection = JDBCTools.getConnection();T t = null;try {t = queryRunner.query(connection, sql, new BeanHandler<T>(type), params);} catch (SQLException e) {//将编译时异常转换为运行时异常向上抛throw new RuntimeException(e);}return t;}/*** 获取所有对象* * @param sql* @param params* @return*/public <T> List<T> getBeanList(Class<T> type,String sql, Object... params) {// 获取连接Connection connection = JDBCTools.getConnection();List<T> list = null;try {list = queryRunner.query(connection, sql, new BeanListHandler<T>(type), params);} catch (SQLException e) {//将编译时异常转换为运行时异常向上抛throw new RuntimeException(e);} return list;}/*** 获取一个单一值的方法,专门用来执行像select count(*)... 这样的sql语句* * @param sql* @param params* @return*/public Object getSingleValue(String sql, Object... params) {// 获取连接Connection connection = JDBCTools.getConnection();Object value = null;try {value = queryRunner.query(connection, sql, new ScalarHandler(), params);} catch (SQLException e) {//将编译时异常转换为运行时异常向上抛throw new RuntimeException(e);}return value;}/*** 进行批处理的方法* 关于二维数组Object[][] params*        二维数组的第一维是sql语句要执行的次数*       二维数组的第二维就是每条sql语句中要填充的占位符* * @param sql* @param params*/public void batchUpdate(String sql , Object[][] params){//获取连接Connection connection = JDBCTools.getConnection();try {queryRunner.batch(connection ,sql, params);} catch (SQLException e) {//将编译时异常转换为运行时异常向上抛throw new RuntimeException(e);}}
}

10.3 DAO实现类

import com.atguigu.bean.User;
import com.atguigu.dao.UserDAO;public class UserDAOImpl extends BasicDAOImpl implements UserDAO{@Overridepublic User getUser(User user) {// 写查询数据库的sql语句String sql = "select id , username , password , email from users where username = ? and password = ?";// 调用BaseDao中的getBean方法User bean = getBean(User.class, sql, user.getUsername(), user.getPassword());return bean;}@Overridepublic boolean checkUserName(User user) {// 写查询数据库的sql语句String sql = "select id , username , password , email from users where username = ?";// 调用BaseDao中的getBean方法User bean = getBean(User.class, sql, user.getUsername());return bean!=null;//不为空,说明已存在,返回true,如果bEan是空的,没找到,bean!=null返回false,说明不存在}@Overridepublic void saveUser(User user) {//写添加数据到数据库的sql语句String sql = "insert into users(username,password,email) values(?,?,?)";//调用BaseDao中通用的增删改的方法update(sql, user.getUsername(),user.getPassword(),user.getEmail());}
}

JDBC 万字长文总结【回炉重造】相关推荐

  1. Vue回炉重造之封装防刷新考试倒计时组件

    你好,我是Vam的金豆之路,可以叫我豆哥.2019年年度博客之星.技术领域博客专家.主要领域:前端开发.我的微信是 maomin9761,有什么疑问可以加我哦,自己创建了一个微信技术交流群,可以加我邀 ...

  2. 机器人学回炉重造(1-2):各种典型机械臂的正运动学建模(标准D-H法)

    文章目录 写在前面 三连杆平面机械臂 平行四边形操作臂 闭链结构 例:平行四边形操作臂 球形臂 拟人臂 球腕 斯坦福机械臂 带球形手腕的拟人化机械臂 DLR机械臂 参考文献 写在前面 本文所有机械臂均 ...

  3. 《回炉重造 Java 基础》——集合(容器)

    整体框架 绿色代表接口/抽象类:蓝色代表类. 主要由两大接口组成,一个是「Collection」接口,另一个是「Map」接口. 前言 以前刚开始学习「集合」的时候,由于没有好好预习,也没有学好基础知识 ...

  4. 机器人学回炉重造(5-2):关节空间规划方法——梯形加减速(与抛物线拟合的线性函数)、S型曲线规划

    文章目录 写在前面 学习代码都记录在[个人github](https://github.com/xuuyann/RobotLearningCode)上,欢迎关注~ 梯形加减速(与抛物线拟合的线性函数) ...

  5. 真人电影中的幻想生物迷墙:索尼克为什么被骂到回炉重造?

    <大侦探皮卡丘>上映在即,当网友们对着雷佳音配音的皮卡丘大呼好萌好萌时,我们仿佛又来到了大型真香现场--明明在几个月之前,当人们看到毛茸茸的大叔音皮卡丘时还每个细胞都充满了拒绝. 也有一种 ...

  6. 机器人学回炉重造(2-4):运动学奇异位型分析

    文章目录 什么是运动学奇异位型? 例子:平面二连杆机械手的奇异位型 奇异位型解耦 腕部奇异位型 手臂奇异位型 转载:6轴串联关节机器人的奇异点 参考文献 什么是运动学奇异位型? 在初步系统地了解了机器 ...

  7. Vue回炉重造之封装一个实用的人脸识别组件

    你好,我是Vam的金豆之路,可以叫我豆哥.2019年年度博客之星.技术领域博客专家.主要领域:前端开发.我的微信是 maomin9761,有什么疑问可以加我哦,自己创建了一个微信技术交流群,可以加我邀 ...

  8. 机器人学回炉重造(2-3):基本雅可比矩阵与其他雅可比矩阵

    文章目录 基本雅可比矩阵 定义 求法 其他雅可比矩阵 定义 求法 补充:几何雅可比与解析雅可比 基本雅可比矩阵 定义 用笛卡尔坐标描述线速度(linear velocity)和角速度(angular ...

  9. 回炉重造之数据结构【一】基本概念

    回炉重造之数据结构[一]绪论 文章目录 回炉重造之数据结构[一]绪论 数据结构的基本概念 基本概念和术语 数据结构的三要素 算法和算法评价 算法的基本概念 算法效率的度量 数据结构的基本概念 基本概念 ...

  10. javacript回炉重造之基础细节点

    ascript之回炉重造 var n5=2e5 2*10的五次方 0x开头十六进制 0o开头八进制 0b开头二进制 typeof 用于检测数据类型 值类型(基本类型):字符串(String).数字(N ...

最新文章

  1. java 怎么让一个jlabel和一个jtextfield在一行_今天小哥大家分享一下Java编程语言的第一个程序应该怎么样去写...
  2. java r$_基于javacv的人脸检测Demo
  3. 清爽娱乐网系统源码 v5.69
  4. 电脑不能打字_书记员速录如何提高打字速度和正确率
  5. linux less命令详解
  6. 自卑都是自己不踏实做事的表现
  7. GB28181学习之路——eXosip获取IP和端口
  8. 英伟达 jetson xavier agx 开发(1)开发环境搭建
  9. kibana本地安装
  10. SQL48 将所有获取奖金的员工当前的薪水增加10%
  11. 第031讲:永久存储,腌制一缸美味的泡菜 | 学习记录(小甲鱼零基础入门学习Python)
  12. 配置IKAnalyzer扩展词库
  13. elementUI 导航栏 鼠标移入改变背景色
  14. Oracle语法求水仙花数,python实现水仙花数实例讲解
  15. 医学图像——医学坐标体系
  16. 佛山Uber优步司机奖励政策(12月21日到12月27日)
  17. Makefile中的奇葩字符
  18. Linux rootfs挂载过程
  19. Excel数据分析:美国牛油果销售分析
  20. 将浏览器设置成夜间模式

热门文章

  1. Juniper入门之简单命令
  2. 快播团队悄然崛起:连获2大奖,业内充分肯定,抢先布局千亿市场
  3. 云主机的公有云、私有云、混合云有什么不同?
  4. javascript中的Data()对象
  5. 龙渊无限法则服务器,龙渊大陆3.0无限法则
  6. 严蔚敏《数据结构》的全部代码实现(C语言)
  7. 华钜同创:亚马逊运营每天需要关注的内容
  8. 国家电网计算机知识点归纳,国家电网知识点
  9. linux系统安装腾达U1无线网卡驱动
  10. 2014 2013 一级建造师视频/建筑/法律/经济/机电/市政/水利/管理