【JDBC】总结与笔记

【JDBC】总结与笔记,第1张

文章目录
  • 一、JDBC概述
  • 二、JDBC快速入门
    • 2.1 JDBC第一个程序
    • 2.2 获得数据库连接的五种方式
    • 2.3 结果集
    • 2.4 Statement接口
      • 2.4.1 Statement(实现对象)
      • 2.4.2 PreparedStatement(预处理)
    • 2.4 JDBC API 学习小结
  • 三、JDBCUtils工具类
  • 四、事务处理
  • 五、批处理
  • 六、数据库连接池
    • 6.1 数据库连接池种类
    • 6.2 C3P0 数据库连接池
    • 6.3 Druid(德鲁伊)数据库连接池
    • 6.4 JDBCUtils类(德鲁伊实现)
  • 七、ApDBUtils工具类
    • 7.1 测试-查询
    • 7.2 测试-DML
  • 八、DAO和BasicDao
    • 8.1 BasicDao类(通用方法类)
    • 8.2 XxxDao类(继承于BasicDao类)

一、JDBC概述

基本介绍:
    1.JDBC为访问不同的数据库提供了统一的接口(标准),为使用者屏蔽了细节问题
 
    2.Java程序员使用 JDBC,可以连接任何提供了 JDBC驱动程序的数据库系统,从而完成对数据库的各种 *** 作。
 
    3.JDBC原理图:

JDBC API:
JDBC是 Java提供一套用于 *** 作数据库 *** 作的接口API,Java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同的实现,相关类和接口在java.sgl与javax.sal包,

 

二、JDBC快速入门

1.注册驱动 - 加载Driver类
2.获取连接 - 得到Connection
3.执行增删改查 - 发送SQL给mysql执行
4.释放资源 - 关闭相关的连接等

2.1 JDBC第一个程序
public class jdbc01 {
    public static void main(String[] args) throws SQLException {

        //前置工作,在项目创建文件夹,如 libs,复制 mysql-connector-java.jar到该文件夹下,并加入到项目中
        // 1.注册驱动
        Driver driver = new Driver(); // 创建driver对象


        // 2.得到连接
            // (1) jdbc:mysql:// 【规定好的,协议,通过jdbc的方式来连接mysql】
            // (2) localhost: 【localhost表示本机,主机。可以是ip地址(非本机)】
            // (3) 3306 【端口号,可能有不同的端口号。如3307】
            // (4) /db1_test 【要 *** 作的具体数据库】
        String url = "jdbc:mysql://localhost:3306/db1_test";
            // 将用户名和密码放入到Properties对象中
        Properties properties = new Properties();
            // 关键字:user、password
        properties.setProperty("user","root"); // 设置用户
        properties.setProperty("password","xxx"); // 密码

        Connection connect = driver.connect(url, properties);


        // 3.执行sql
        String sql = "INSERT INTO employees() VALUES(12,'小明','15000','男'),(11,'小红','10000','女')";
            // Statement对象( *** 作数据库的对象) 用于执行静态sql语句,并返回其生成的结果的对象
        Statement statement = connect.createStatement();
        int rows = statement.executeUpdate(sql); // 大于0,返回影响行数。否则执行失败

        System.out.println(rows>0?"成功":"失败");

        // 4.关闭连接资源
        statement.close();
        connect.close();
    }
}

 

2.2 获得数据库连接的五种方式

第一种:

静态加载Driver类

public void connect01() throws SQLException {
	// 获取Driver实现类对象
	Driver driver = new com.mysql.jdbc.Driver()
	
	// 连接地址
	String url = "jdbc:mysql://localhost:3306/db1_test";
	
	// 用户: 用户名和密码
	Properties info = new Properties();
	info.setProperty("user","root");
	info.setProperty("password","xxx");
	
	// 填入 连接地址(url)和 用户(info),得到连接
	Connection conn = driver.connect(url,info);
	System.out.println(conn);
}

 
第二种:

动态加载Driver类,使用反射加载

// 方式 1会直接使用 com.mysql.jdbc.Driver0,属于静态加载,灵活性差,依赖强
// --推出-->方式2
 public void connect02() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
     Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
     Driver driver = (Driver)aClass.newInstance();

     String url = "jdbc:mysql://localhost:3306/db1_test";

     Properties info = new Properties();
     info.setProperty("user","root");
     info.setProperty("password","xxx");

     Connection conn = driver.connect(url,info);
     System.out.println(conn);
 }

 
第三种:

使用DriverManager替代Diver进行统一管理

public void connect03() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
	 // 使用反射加载Driver
	 Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
	 Driver driver = (Driver) aClass.newInstance();
   	 
	 // 创建 url 和 user 和 password
	 String url = "jdbc:mysql://localhost:3306/db1_test";
	 String user = "root";
	 String password = "xxx";

   	 DriverManager.registerDriver(driver); // 注册Driver驱动
	
	// 得到连接
	 Connection connection = DriverManager.getConnection(url, user, password);
	 System.out.println(connection);
}

 
第四种:

使用Class.forName自动完成注册驱动,简化代码=>分析源码

public void connect04() throws ClassNotFoundException, SQLException {
	// 使用反射加载了 Driver类
	Class.forName("com.mysql.jdbc.Driver");

	// 创建 url 和 user 和 password
	String url = "jdbc:mysql://localhost:3306/db1_test";
	String user = "root";
	String password = "xxx";
	
	// 得到连接
	Connection conn = DriverManager.getConnection(url,user,password);
	System.out.println(conn);
}

 
MySQL驱动5.1.6可以无需CLass.forName(“com.miysql.jdbc.Driver");从jdk1.5以后使用了jdbc4,不再需要显示调用class.forName(0注册驱动而是自动调用驱动jar包下META-INF\services\java.sql.Driver文本中的类名称去注册
但建议还是写上CLass.forName('com.mysql.jdbc.Driver",更加明确

 
第五种(开发建议使用):

方式5,在方式4的基础上改进,增加配置文件,让连接ysqL更加灵活

配置properties文件: 复制到 src目录下

user=root
password=xxx
url=jdbc:mysql://Localhost:3306/db1_test
driver=com.mysql.jdbc.Driver
public static void connect05() throws IOException, ClassNotFoundException, SQLException {
	// 通过Properties,对象获取配置文件的信息
	Properties properties = new Properties();
	properties.load(new FileInputStream("test_sql\src\mysql.properties"));
	
	// 获取相关的值
	String url = properties.getProperty("url");
	String user = properties.getProperty("user");
	String password = properties.getProperty("password");
	String driver = properties.getProperty("driver");
	
	Class.forName(driver);
	
	Connection connection = DriverManager.getConnection(url,user,password);
	System.out.println(connection);
}

 

2.3 结果集

 

2.4 Statement接口

Statement是一个接口,位于 java.sql包下,它被不同的厂商实现

// 返回的是实现了Statement接口的实例化对象,不同的厂商的返回的实现类对象不同
Statement statement = connection.createStatement();
PreparedStatement preparedStatement = connection.prepareStatement(sql);

 

2.4.1 Statement(实现对象)


 

2.4.2 PreparedStatement(预处理)

String sql = “SELECT COUNT(*) FROM admin WHERE username = ? AND PASSWORD=?”;
 
1.PreparedStatement执行的SQL语句中的参数用问号(?)来表示,调用PreparedStatement对象的setXxx0方法来设置这些参数.setXxx0方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值
2.调用executeQuery(),返▣ResultSet对象
3.调用executeUpdate0:执行更新,包括增、删、修改
 
预处理好处
1.不再使用 +拼接 sq语句,减少语法错误
2.有效的解决了 sql注入问题!
3.大大减少了编译次数,效率较高

...
// 组织 sql,sql中的 ? 相当于占位符
String sql = "select * from employees where user = ? and password = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);

// 给占位符赋值
prepareStatement.setString(1,"root");
prepareStatement.setString(2,"xxx");

// 执行select语句使用executeQuery
// 如果执行的是 增删改 DML(update,insert,delete),用 executeUpdate()
// 这里不用写sql,如果写了就是原来的sql,字符串的不变性
ResultSet resultSet = prepareStatement.executeQuery();
...
...
String sql = "insert into admin values(?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);

prepareStatement.setString(1,"1");
prepareStatement.setString(2,"这是内容");

ResultSet resultSet = prepareStatement.executeUpdate();
...

 

2.4 JDBC API 学习小结



返回的实例化对象,都是厂商实现了该类的实现类对象

 

三、JDBCUtils工具类

在dbc *** 作中,获取连接和释放资源是经常使用到可以将其封装DBC连接的工具类JDBCUtils
 
JDBCUtils是一个工具类,完成 mysql的连接和关闭

public class JDBCUtils {
    // 定义相关的属性(4个),因为只需要一份,因此,我们做出static
    public static String url; // url
    public static String user; // 用户
    public static String password; // 密码
    public static String driver; // 驱动

    // static 代码块初始化
    static {
        Properties properties = new Properties();
        try {
        	// 加载配置文件
            properties.load(new FileInputStream("test_sql\src\mysql.properties"));

            // 读取属性值
            String url1 = properties.getProperty("url");
            String user1 = properties.getProperty("user");
            String password1 = properties.getProperty("password");
            String driver1 = properties.getProperty("driver");
        } catch (IOException e) {
            // 实际开发可以这样处理
            // 1.将编译异常转为运行异常
            // 2.这时候调用者 可以选择捕获该异常,也可以选择默认处理该异常,比较方便。
            throw new RuntimeException(e);
        }
    }

    // 连接数据库,返回 Connection
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /*	关闭资源
        1.resultSet 结果集
        2.Statement 或者 PreparedStatement
        3.Connection
        4.需要关闭传入 null,否则传入对象
     */
    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) {
            throw new RuntimeException(e);
        }
    }
}
public class Main {

    public static void testDML(){ // insert、update、delete

        Connection connection = null;

        String sql = "update news set content = ? where id = ?";

        PreparedStatement preparedStatement = null;


        try {
            connection = JDBCUtils.getConnection();

            preparedStatement = connection.prepareStatement(sql);

            preparedStatement.setString(1, "q");
            preparedStatement.setInt(2, 1);

            preparedStatement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }
}

 

四、事务处理

基本介绍
1.JDBC程序中当一个 Connection对像创建时,默认情况下是自动提交事务:每次执行一个>SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
2.JDBC程序中为了让多个SQL语句作为一个整体执行,需要使用事务
3.调用 Connection的 setAutoCommit(false)可以取消自动提交事务
4.在所有的SQL语句都成功执行后,调用 Connection的 commit()方法提交事务
5.在其中某个 *** 作失败或出现异常时,调用 Connection的 rollback()方法回滚事务

示例: (把张三的100给到李四,这时候为了数据的一致性,需要用到事务处理)

CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(32) NOT NULL DEFAULT '',
balance DOUBLE NOT NULL DEFAULT 0) CHARACTER SET utf8;

INSERT INTO account VALUES(NULL,'张三', 3000);
INSERT INTO account VALUES(NULL,'李四', 10000);
public class transaction01 {

    public static void use_transaction() {

        Connection connection = JDBCUtils.getConnection();

        PreparedStatement preparedStatement = null;
        PreparedStatement preparedStatement1 = null;
        try {
            connection.setAutoCommit(false); // connection执行 sql语句默认自动提交。设置为 false开启事务

            String sql1 = "update account set balance = balance - 100 where id = 3";
            String sql2 = "update account set balance = balance + 100 where id = 4";

            preparedStatement = connection.prepareStatement(sql1);
            preparedStatement.executeUpdate(); // 执行第一条

//            int i = 1/0; 异常

            preparedStatement1 = connection.prepareStatement(sql2);
            preparedStatement1.executeUpdate(); // 执行第二条

            connection.commit();
        } catch (Exception e) {
            try {
                System.out.println("执行发生异常,回滚sql语句");
                connection.rollback(); // 当出现异常时,catch捕获,执行回滚 *** 作默认回滚到事务开始的,可以设置保存点(connection.setSavepoint("a保存点");)
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            try {
                preparedStatement.close();
                preparedStatement1.close();
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) {
        use_transaction();
    }
}

 

五、批处理

基本介绍
1.当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允
许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
 
2.JDBC的批量处理语句包括下面方法:
addBatch(:添加需要批量处理的SQL语句或参数
executeBatch():执行批量处理语句;
clearBatch():清空批处理包的语句
 
3.JDBC连接 MySQL时,如果要使用批处理功能,需要在 url中加入参数
?rewriteBatchedStatements=true
 
4.批处理往往和 PreparedStatement 一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高

 
示例:
未使用批处理,往 news表中添加5000条数据:

CREATE TABLE news(
id INT,
content VARCHAR(10)
);
public class Batch01 {
    public static void main(String[] args) throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into news values (?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        long start = System.currentTimeMillis();

        for(int i=1;i<=5000;i++){
            preparedStatement.setInt(1,i);
            preparedStatement.setString(2,"新闻内容");
            preparedStatement.executeUpdate();
        }

        long end = System.currentTimeMillis();
        System.out.println("执行时间: "+ (end - start) + "ms");
        /* 执行时间: 6804ms */

        JDBCUtils.close(null, preparedStatement, connection);
    }
}

 
使用批处理:

public class Batch01 {
    public static void main(String[] args) throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into news values (?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        long start = System.currentTimeMillis();

        for(int i=1;i<=5000;i++){
            preparedStatement.setInt(1,i);
            preparedStatement.setString(2,"新闻内容");
            // 将 sql语句加入批处理包中
            preparedStatement.addBatch();
            // 当有 1000条 sql语句时,将批处理包发送给 mysql执行
            if(i%1000 == 0){
                preparedStatement.executeBatch(); // 批量执行
                preparedStatement.clearBatch(); // 清空
            }
        }

        long end = System.currentTimeMillis();
        System.out.println("执行时间: "+ (end - start) + "ms");
        /* 执行时间: 139ms */

        JDBCUtils.close(null, preparedStatement, connection);
    }
}

可以发现,执行速度提升了近50倍.

 

六、数据库连接池

传统 Connection问题分析:
1.频繁的进行数据库连接 *** 作将占用很多的系统资源,容易造成服务器崩溃。
 
2.每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库内存泄漏,最终将导致重启数据库。
 
3.传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致内存泄漏,MySQL崩溃。
 
4.解决传统开发中的数据库连接问题(无缓冲),可以采用数据库连接池技术(connection pool)

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

 

6.1 数据库连接池种类

1.JDBC的数据库连接池使用 javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供实现(不同的数据库连接池技术实现方式不一样)
 
2.C3P0数据库连接池,速度相对饺慢,稳定性不错(hibernate,spring)
 
3.DBCP数据库连接池,速度相对c3p0较快,但不稳定
 
4.Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
 
5.BoneCP数据库连接池,速度快
 
6.Druid(德鲁伊) 是阿里提供的数据库连接池,集DBCP、C3P0、Proxool优点于一身的数据库连接池

 

6.2 C3P0 数据库连接池

方式一:相关的参数在程序中指定(url,user,password等)

public class c3p0_test {

    public static void test() throws IOException, PropertyVetoException, SQLException {
    	// 加入c3p0jar包,properties配置文件
        // 1.创建一个数据源对象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        // 2.通过配置文件(mysql.properties)获取相关的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("test_sql\src\mysql.properties"));

        // 3.获取相关的属性值
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");

        // 4.给数据源 comboPooledDataSource设置参数(连接的创建和管理交给comboPooledDataSource)
        comboPooledDataSource.setJdbcUrl(url); // url
        comboPooledDataSource.setUser(user); // user
        comboPooledDataSource.setPassword(password); // password
        comboPooledDataSource.setDriverClass(driver); // driver

        comboPooledDataSource.setInitialPoolSize(5); // 设置初始化连接数
        comboPooledDataSource.setMaxPoolSize(50); // 设置最大连接数(超出最大连接数时的连接,会进入等待队列。不会创建新的连接)

        // 5.获得连接
        Connection connection = comboPooledDataSource.getConnection();// 实现 DataSource接口的方法
        System.out.println("连接成功" + connection);

        connection.close();
    }

    public static void main(String[] args) throws PropertyVetoException, SQLException, IOException {
        test();
    }
}

 
方式二: 使用配置文件模板来完成
配置文件模板:

<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
  <default-config>
    <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
    <property name="user">root</property>
    <property name="password">xxx</property>
    
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">50</property>
    <property name="checkoutTimeout">3000</property>
  </default-config>

  <named-config name="ihihr">
  </named-config>
</c3p0-config>
public class c3p0_test02 {

    public static void test() throws SQLException {
    
        // 将c3p0提供的c3p0.config.XmL拷贝到src目录下(该文件指定了连接数据库和连接池的相关参数)
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("ihihr");

        Connection connection = comboPooledDataSource.getConnection();
        System.out.println(connection);
    }

    public static void main(String[] args) throws SQLException {
        test();
    }
}

 

6.3 Druid(德鲁伊)数据库连接池

配置文件模板:

#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://Localhost:3306/test?rewriteBatchedstatements=true
#url=jdbc:mysql://Localhost:3306/test
username=root
password=xxx
#initial connection Size
initialsize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000
public class Druid01 {

    public static void test() throws Exception {
        //1.加入Druid jar包
        //2.加入配置文件dru1d.properties,将该文件拷贝项目的src目录
        //3.创建properties对象读取配置文件
        Properties properties = new Properties();
      	// 当有多个子项目时,需要指明是那个子项目的 src目录
        properties.load(new FileInputStream("test_sql\src\druid.properties"));

        //4.创建一个指定配置文件参数的数据源(数据库连接池)
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        //5.得到连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }

    public static void main(String[] args) throws Exception {
        test();
    }
}

 

6.4 JDBCUtils类(德鲁伊实现)
public class JDBCUtilsByDruid {

    private static DataSource dataSource;

    // 静态代码块完成初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("test_sql\src\druid.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 得到连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 关闭连接(放回连接池)(Connection是接口! 这里的connection.close()方法
    // 并不是原来mysql实现的connection.close()方法,而是Druid(德鲁伊)实现的connection.close()方法,仅仅只是放回连接池)
    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) {
            throw new RuntimeException(e);
        }
    }
}

 

七、ApDBUtils工具类

引入:
1.关闭 connection后,resultSet结果集无法使用
2.resultSet不利于数据的管理
3.使用结果集中的数据也不方便(getInt(…)、getString(…))

表对应类:JavaBean类(Domain类,POJO类),一个对象对应一条记录,再将对象(记录)封装到 ArrayList中,


 
Apache–DBUtils类库

基本介绍:
1.commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的封装,使用dbutils能极大简化jdbc编码的工作量。
 
DbUtils类:
1.QueryRunner类:该类封装了SQL的执行,是线程安全的。可以实现增、删、改、查、批处理
2.使用QueryRunner类实现查询
3.sultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式
 
ArrayHandler: 把结果集中的第一行数据转成对象数组。
ArrayListHandler: 把结果集中的每一行数据都转成一个数组,再存放到List中。
BeanHandler: 将结果集中的第一行数据封装到一个对应的JavaBean实例中。
BeanListHandler: 将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
ColumnListHandler: 将结果集中某一列的数据存放到List中。
KeyedHandler(name): 将结果集中的每行数据都封装到Map里,再把这些map再存到一个map里,其key为指定的key。
MapHandler: 将结果集中的第一行数据封装到一个Map里,key是列名,vaue就是对应的值。
MapListHandler: 将结果集中的每一行数据都封装到一个Map里,然后再存放到List

 
示例: (使用 DBUtils + 德鲁伊(数据库存连接池)的方式完成对 news表的增、删、查、改)

news表:

CREATE TABLE news(
INT id,
content VARCHAR(10)
);

properties配置文件:

#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://Localhost:3306/test?rewriteBatchedstatements=true
#url=jdbc:mysql://Localhost:3306/test
username=root
password=xxx
#initial connection Size
initialsize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000

引用的库:

[commons-dbutils-1.7.jar][druid-1.0.10.jar][mysql-connector-java-8.0.29.jar]

news–JavaBean类:

public class news {

    private Integer id;
    private String content;

    public news(){
    }

    public news(Integer id, String content) {
        this.id = id;
        this.content = content;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "news{" +
                "id=" + id +
                ", content='" + content + '\'' +
                '}';
    }
}

JDBCUtilsByDruid工具类:

public class JDBCUtilsByDruid {

    private static DataSource dataSource;

    // 静态代码块完成初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("test_sql\src\druid.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 得到连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 关闭连接(放回连接池)(Connection是接口! 这里的connection方法并不是原来mysql实现的connection方法,而是Druid(德鲁伊)实现的connection方法)
    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) {
            throw new RuntimeException(e);
        }
    }
}

 

7.1 测试-查询

查询(返回多条记录)

public class dbutils_druid01 {

    // 返回多条结果
    public static void testQueryMany() throws SQLException {
    	// 使用DBUtils类和接口,引入DBUtils相关的jar,加入到本Project
    	
        // 1.得到连接
        Connection connection = JDBCUtilsByDruid.getConnection();
        
        // 2.创建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        
        // 3.执行相关的方法,返回ArrayList结果集
        String sql = "select * from news where id >= ?";
        //(1) query方法就是执行sgL语句,得到resultset---封装到-->ArrayList集合中
        //(2) 返回集合
        //(3) connection:连接
        //(4) sgL:执行的sgL语句
        //(5) new BeanListHandler<>(Actor,class):在将resultset-> Actor对象->封装到ArrayList
        // 底层使用反射机制 去获取Actor进行封装
        //(6) 1是给sqL语句中的?赋值,可以有多个值,因为是可变参数
        //(7) 底层得到的resultSet方法,会在query方法中关闭, 还会关闭PreparedStatement,因为底层就是用PreparedStatement完成dml
        List<news> list = queryRunner.query(connection, sql, new BeanListHandler<>(news.class), 1);
        
        for(news n:list){
            System.out.println(n);
        }

        JDBCUtils.close(null, null, connection);
    }

    public static void main(String[] args) throws SQLException {
        testQueryMany();
    }
}

 
查询(返回单条记录)

...
String sql = "select * from news where id = ?";
QueryRunner queryRunner = new QueryRunner();
// 因为返回的是单个记录, 使用的 Handler是 BeanHandler
news ne = queryRunner.query(connection, sql, new BeanHandler<>(news.class), 2);
...

 
查询(返回单行单列)

...
String sql = "select content from news where id = ?";
QueryRunner queryRunner = new QueryRunner();
// Scalar表示的意思就是单行单列,返回 Object类型
Object obj = queryRunner.query(connection, sql, new ScalarHandler<>(), 2);
...

 

7.2 测试-DML
public class dbutils_druid03 {
    public static void testDML() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();

        QueryRunner queryRunner = new QueryRunner();

        String sql = "update news set content = ? where id = ?";
        String sql2 = "insert into news values (?, ?)";
        String sql3 = "delete from news where id = ?";

        //(1) 执行 DML *** 作的是 update()方法
        //(2) 返回影响行数(affected: 受影响)
        int affectedRow = queryRunner.update(connection, sql, "新闻", 1);
        System.out.println(affectedRow>0?"执行成功":"执行没有影响到表");

        int affectedRow2 = queryRunner.update(connection, sql2, 3, "内容3");
        System.out.println(affectedRow2>0?"执行成功":"执行没有影响到表");

        int affectedRow3 = queryRunner.update(connection, sql3, 3);
        System.out.println(affectedRow2>0?"执行成功":"执行没有影响到表");

        JDBCUtilsByDruid.close(null, null, connection);
    }

    public static void main(String[] args) throws SQLException {
        testDML();
    }
}


 

八、DAO和BasicDao

引入BasicDao:
apache-dbutils + Druid简化了JDBC开发,但还有不足:
1.SQL语句是固定,不能通过参数传入,通用性不好,需要进行改进,更方便执行增删改查
2.对于select *** 作,如果有返回值,返回类型不能固定,需要使用泛型
3.将来的表很多,业务需求复杂,不可能只靠一个Java类完成
 
Dao: 进行数据 *** 作的类, 是对于数据库中的表的数据做增删改查等 *** 作的类。
基本说明:
1.DAO:data access obje数据访问对象
2.这样的通用类,称为BasicDao,是专门和数据库交互的,即完成对数据库(表)的crud *** 作。
3.在BaiscDao的基础上,实现一张表对应一个Dao,更好的完成功能,比如Customer表-
Customer.java(javabean)-CustomerDao.java

 
示例:

在开发中,通常分为三层架构:
数据层访问层 – MySQL数据库、JavaBean类、、dao类
service层(业务逻辑层)
view层(界面层)
 
以下示例:dao类

 

8.1 BasicDao类(通用方法类)
public class BasicDAO<T> {

    private QueryRunner qr = new QueryRunner();

    // 开发通用的 dml *** 作方法
    public int update(String sql, Object... parameters) {
        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            int update = qr.update(connection, sql, parameters);
            return update;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

    /**
     * 返回多个对象(多行)的通用方法
     * @param sql sql语句,可以有 ?
     * @param clazz 传入一个类的 Class对象,比如:news.class
     * @param parameters 传入 ? 的具体的值,可以是多个
     * @return 根据 news.class 返回对应的 ArrayList集合
     */
    public List<T> queryMany(String sql, Class<T> clazz, int parameters){
        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection, sql, new BeanListHandler<>(clazz), parameters); // List query
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

    // 查询单行结果的通用方法
    public T querySingle(String sql, Class<T> clazz, Object... parameters){
        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection, sql, new BeanHandler<>(clazz), parameters); // T Query
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

    // 返回单行单列的通用方法
    public Object queryScalar(String sql, Object... parameters){
        Connection connection = null;

        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection, sql, new ScalarHandler<>(), parameters);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JDBCUtilsByDruid.close(null, null, connection);
        }
    }

}

 

8.2 XxxDao类(继承于BasicDao类)
public class newsDao extends BasicDAO<news> {
    // 1.有了BasicDao的方法
    // 2.根据业务需求,可以编写特有的方法

    // 修改 news其中一条记录
    public int ModifyNews_content(int id,String content){
        String sql = "update news set content = ? where id = ?";
        int update = super.update(sql, content, id);
        return update;
    }
    
	// 增加一条新闻
	...
}

 
测试:

public class test{

    // 修改新闻 id为 7的新闻内容
    public static void test(){
        newsDAO n = new newsDAO();
        int id = 7;
        String content = "新的内容";
        int result = n.ModifyNews_content(7,content);
        System.out.println(result>0?"修改成功":"修改不成功");
    }

    public static void main(String[] args) {
        test();
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/876725.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存