还犹豫什么?这篇JDBC足够了!带你全面理解,从小白到精英(50k字只为博得君一赞)

 欢迎来到@一夜看尽长安花 博客,您的点赞和收藏是我持续发文的动力

对于文章中出现的任何错误请大家批评指出,一定及时修改。有任何想要讨论的问题可联系我:3329759426@qq.com 。发布文章的风格因专栏而异,均自成体系,不足之处请大家指正。

    专栏:

文章概述

关键词:JDBC

本文目录

 

JDBC概述

1.数据的持久化

2.java 三大平台:

3.什么是 JDBC:

4.什么是数据库驱动程序:

5.Java中访问数据库技术:

6.Driver 接口

 7. JDBC URL

          1.连接 MySql 数据库:

           2.连接 Oracle 数据库:

8.Connection 接口

9.Statement 接口

10.PreparedStatement接口

11.ResultSet 接口

JDBC编写步骤​编辑

获取连接                                       ​

环境:

准备工作:

下载数据库驱动

获取数据库连接

        1.常见问题:

        2.解决方法:

        3.问题分析:

        4.useSSL设置成false和true的区别:

Properties文件的使用

优化获取数据库的连接​编辑

优化连接数据库

封装JDBC工具类

Statement的使用

通过Statement 添加数据

 Statement修改用户信息

删除数据

PreparedStatement对象简介(重点):

PreparedStatement对象的特点:

PreparedStatement 的预编译能力:

Preparement 添加数据

更新数据

删除数据

ResultSet

ResultSet接口的特点:

ResultSet特点:

ORM编程思想

ORM简介:

ORM使用

Sql注入

问题:SQL注入:

解决sql 注入

 批量添加数据简介

数据的批量添加

修改配置

JDBC事务

1.事务简介

        1.事务:

        2.事务操作流程:

2.JDBC中事务处理特点:

JDBC事务的实现

 模糊查询

动态条件查询

分页查询

问题:如何在MySql中实现物理分页查询?

解决方法:

连接数据库:

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

JDBC数据库连接池的必要性:

数据库连接池的优点:

常用的数据库连接池:

Druid简介

Druid使用步骤:

druid 封装工具类

应用程序分层

分层优点:

分层命名:

基于Driuid封装工具类:

问题一:

问题分析:

问题二:

问题解决:

应用程序分层实现

分层实现

数据层:

业务层:

web层

封装通用的DML操作

封装实现类

userdao接口

userdao实现类

usersservice接口

 usersService实现类

封装通用的查询语句

在BaseDao的实现类里实现抽象方法:

1.通过反射先去实例化这个实体类对象:

2.返回泛型对象  :

BaseDao实现类

UserDao接口

UserDao的实现类

Userservice接口

UserService实现类

     对象关联关系

关联关系简介:

关联关系的方向性:

创建对象

创建表

建立三者双向关系

Users

orders

items

使用关联对象存放查询数据

UserDao:

UsersDaoImpl:

UsersService:

UserServixeImpl:

    

JDBC概述

1.数据的持久化

1.持久化(persistence):将内存中的数据保存到可永久保存的存储
设备中(如磁盘)
2.持久化的主要应用是将内存中的数据存储在关系型数据库中,当
然也可以存储在磁盘文件、XML数据文件中

2.java 三大平台:

SE ME EE

3.什么是 JDBC:

  1. JDBC(Java DataBase Connectivity)java 数据库连接
  2. 是 JavaEE 平台下的技术规范
  3. 定义了在 Java 语言中连接数据库,执行 SQL 语句的标准 API
  4. 可以为多种关系数据库提供统一访问

4.什么是数据库驱动程序:

  1. 数据库驱动就是直接操作数据库的一个程序
  2. 不同数据产品的数据库驱动名字有差异
  3. 在程序中需要依赖数据库驱动来完成对数据库的操作

5.Java中访问数据库技术:

  1. 基于JDBC标准访问数据库
  2. 使用第三方ORM 框架,如Hibernate, Mybatis 等访问数据库

6.Driver 接口

        1.Driver 接口
Driver 接口的作用是来定义数据库驱动对象应该具备的一些能力。比如与数据库建立连接的方法的定义,该接口是提供给数据库厂商使用的,所有支持java 语言连接的数据库都实现了该接口,实现该接口的类我们称之为数据库驱动类
        2.DriverManager 类
DriverManager是驱动程序管理器,是负责管理数据库驱动程序的。驱动注册以后,会保存在DriverManager中的已注册列表中。 DriverManager 通过实例化的数据库驱动对象,能够建立应用程序与数据库之间建立连 接。并返回 Connection 接口类型的数据库连接对象
 getConnection(String jdbcUrl, String user, String password)
该方法通过访问数据库的 url、用户以及密码,返回对应的数据库的 Connection 对象。

 7. JDBC URL

与数据库连接时,用来连接到指定数据库标识符。在 URL 中包括了该数据库的 类型、 地址、端口、库名称等信息。不同品牌数据库的连接 URL 不同

          1.连接 MySql 数据库:

# 类型    主机  端口  数据库路径  
Connection conn =
DriverManager.getConnection("jdbc:mysql://host:port/database", "user",
"password");     

           2.连接 Oracle 数据库:

  # 类型 关键字 主机IP地址 端口 链接地址
Connection conn =             
DriverManager.getConnection("jdbc:oracle:thin:@host:port:database",
"user", "password");

8.Connection 接口

Connection 是数据库的连接(会话)对象。对数据库的一切操
作都是在这个连接基础之上进行的,我们可以通过该对象执行
sql 语句并返回结果
          常用方法
1.createStatement()
创建向数据库发送 sql 的 Statement 接口类型的对象。
2.preparedStatement(sql)
创建向数据库发送预编译 sql 的 PrepareSatement 接口类型的对象。
3.setAutoCommit(boolean autoCommit)
设置事务是否自动提交。
4.commit()
在链接上提交事务。
5.rollback()
在此链接上回滚事务。

9.Statement 接口

用于执行静态 SQL 语句并返回它所生成结果的对象。 由
createStatement 创建,用于发送简单的 SQL 语句(不支持动
态绑定)(不能用占位符等代替参数,应该要实现绑定好参数)。
             常用方法
1.execute(String sql)
执行参数中的 SQL,返回是否有结果集。
2.executeQuery(String sql)
运行 select 语句,返回 ResultSet 结果集。
3.executeUpdate(String sql)
运行 insert/update/delete 操作,返回更新的行数。
4.addBatch(String sql)
把多条 sql 语句放到一个批处理中。
5.executeBatch()
向数据库发送一批 sql 语句执行。

10.PreparedStatement接口

继承自 Statement 接口,由 preparedStatement 创建,用于发
送含有一个或多个参数的 SQL 语句。PreparedStatement 对象
比 Statement 对象的效率更高,由于实现了动态的参数绑定,
所以可以防止 SQL 注入,所以我们一般都使用
PreparedStatement。
                    常用方法
1.addBatch()
把当前 sql 语句加入到一个批处理中。
2.execute()
执行当前 SQL,返回个 boolean 值
3.executeUpdate()
运行 insert/update/delete 操作,返回更新的行数。
4.executeQuery()
执行当前的查询,返回一个结果集对象
5.setDate(int parameterIndex, Date x)
向当前SQL语句中的指定位置绑定一个java.sql.Date值
6.setDouble(int parameterIndex, double x)
向当前 SQL 语句中的指定位置绑定一个 double值
7.setFloat(int parameterIndex, float x)
向当前 SQL 语句中的指定位置绑定一个 float 值
8.setInt(int parameterIndex, int x)
向当前 SQL 语句中的指定位置绑定一个 int 值
9.setString(int parameterIndex, String x)
向当前 SQL 语句中的指定位置绑定一个 String 值        

11.ResultSet 接口

ResultSet 用来暂时存放数据库查询操作获得结果集
               常用方法
1.getString(int index)、getString(String columnName)
获得在数据库里是 varchar、char 等类型的数据对象。
2.getFloat(int index)、getFloat(String columnName)
获得在数据库里是 Float 类型的数据对象。
3.getDate(int index)、getDate(String columnName)
获得在数据库里是 Date 类型的数据。
4.getBoolean(int index)、getBoolean(String columnName)
获得在数据库里是 Boolean 类型的数据。
5.getObject(int index)、getObject(String columnName)
获取在数据库里任意类型的数据。      
  

JDBC编写步骤

  • 获取连接                                      

环境:

  1. 数据库Mysql5.7
  2. 数据库驱动版本5.1.48
  3. 数据库名itbz

准备工作:

  1. 新建JavaProject工程
  2. 添加数据库驱动jar包   
  3. 获取数据库连接对象

下载数据库驱动

  • 获取数据库连接

        1.常见问题:

获取数据库连接测试的时候报这个错,是啥意思?

        2.解决方法:

String url = "jdbc:mysql://localhost:3306/itbz?useSSL=false";

        3.问题分析:

use SSL是什么?
SSL全称(Secure Sockets Layer ),在外面连接mysql的时候,版本若是在5.7之前,就不用加这个useSSL,若是大于5.7,则需要添加useSSL。默认是false。

        4.useSSL设置成false和true的区别:

设置成true:是进行安全验证,一般需要通过一些证书或者令牌。
设置成false:直接通过账号密码连接,所以通常使用useSSL=false!【在linux系统里面一定要加这个配置】
package com.itbaizhan;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
 * 获取数据库连接测试类
 */
public class JdbcTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //连接Mysql数据库的url
        String url = "jdbc:mysql://localhost:3306/itbz?useSSL=false";
        //连接数据库的用户名
        String name = "root";
        //连接数据库的密码
        String pwd = "root" ;
        //通过反射实现数据库驱动的加载与注册
        Class.forName("com.mysql.jdbc.Driver");
        //通过DriverManager对象获取数据库的连接对象
        Connection connection= DriverManager.getConnection(url,name,pwd);
        System.out.println(connection);
    }
}
在加载com.mysql.jdbc.Driver类信息时,会执行静态块中的代码。在静态块中 ,数据库驱动会实例化自己并通过DriverManager的registerDriver方法,将自己注册DriverManager驱动管理器中。
  • Properties文件的使用

1.properties文件介绍:
后缀properties的文件是一种属性文件。这种文件以key=value格式
存储内容。Java中可以使用Properties工具类来读取这个文件。项
目中会将一些配置信息放到properties文件中,所以properties文
件经常作为配置文件来使用
2.Properties工具类:
Properties工具类,位于java.util包中,该工具类继承自
Hashtable<Object,Object>。通过Properties工具类可以读
取.properties类型的配置文件。
3.Properties工具类中常用方法:
load(InputStream is)
通过给定的输入流对象读取properties文件并解析
getProperty(String key)
根据key获取对应的value
注意:如果properties文件中含有中文那么需要对idea进行设置。
package com.itbaizhan;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
package com.itbaizhan;
import java.io.IOException;
import java.util.Properties;
import java.io.InputStream;
/**
 * 读取properties配置文件的测试类
 */
public class PropertiesTest {
    public static void main(String[] args) throws IOException {
        //将类实例化成对象
        Properties  prop = new Properties();
        //获取读取properties 文件的输入流对象
         InputStream is=PropertiesTest.class.getClassLoader().getResourceAsStream("test.properties");
        //通过给定的输入流对象读取properties文件并解析
        prop.load(is);
        //获取properties 文件中的内容
        String values1 = prop.getProperty("key1");
        String values2 = prop.getProperty("key2");
        System.out.println(values1+" " + values2 );
    }
}

  • 优化获取数据库的连接

将可变数据放在一个文件里,文件是可以改变的
#连接mysql数据库的URL
url = jdbc:mysql://localhost:3306/itbz?useSSL=false
#连接数据库的用户名
name =root
#连接数据库的密码
pwd= root
#数据库驱动名称
driver=com.mysql.jdbc.Driver

优化连接数据库

package com.itbaizhan;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
 * 优化获取数据库连接
 */
public class JdbcTest2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
        //将数据从properties文件中读取出来,所以要先实例化Properties对象
        Properties prop =new Properties();
        //获取读取properties文件的字节输入流对象
        InputStream is = JdbcTest2.class.getClassLoader().getResourceAsStream("jdbc.properties");
        //读取properties文件并解析
        prop.load(is);
        //获取连接数据库的url
        String url = prop.getProperty("url");
        //获取连接数据库的用户名
        String name  = prop.getProperty("name");
        //获取连接数据库的密码
        String pwd  = prop.getProperty("pwd");
        //获取连接数据库驱动全名
        String drivername  = prop.getProperty("driver");
        //加载并注册驱动
        Class.forName(drivername);
        //通过驱动管理器对象获取连接对象
        Connection connection = DriverManager.getConnection(url,name,pwd);
        System.out.println(connection);
    }
}
  • 封装JDBC工具类

package com.itbaizhan;
import jdk.internal.dynalink.beans.StaticClass;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
 * Jdbc工具类
 */
public class JdbcUtils {
    private static String url;
    private static String name;
    private static String pwd;
    //io流操作不能经常进行,否则影响服务器性能
    static {
        try {
            //实例化Properties对象
            Properties prop = new Properties();
            //获取读取properties文件的字节输入流对象
            InputStream is =JdbcTest2.class.getClassLoader().getResourceAsStream("jdbc.properties");
            //读取properties文件并解析
            prop.load(is);
            //获取连接数据库的url
            url = prop.getProperty("url");
            name = prop.getProperty("name");
            pwd = prop.getProperty("pwd");
            //获取数据库的密码
            String drivername= prop.getProperty("driver");
            //加载并注册驱动
            Class.forName(drivername);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取数据库连接对象(所有工具类的方法都是静态方法),通过类.方法名可以直接调用
    public static Connection getConnect(){
        Connection connection = null;
        //通过数据库驱动管理器获取数据库连接
        try {
            connection=DriverManager.getConnection(url,name,pwd);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }
    //关闭连接对象
    public static void closeConnection(Connection connection){
        try {
            connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    //提交事务
    public static void commit(Connection connection){
        try {
            connection.commit();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    //事务回滚
    public static void rollback(Connection connection){
        try {
            connection.rollback();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    //关闭Statement对象
    public static void closeStatement(Statement statement){
        try {
           statement.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    //关闭ResultSet
    public static void closeResultSet(ResultSet resultSet){
        try {
            resultSet.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    //DMl操作时关闭资源
    public static void closeResource(Statement statement,Connection connection){
        //先关闭Statement对象
        closeStatement(statement);
        //再关闭Connection对象
        closeConnection(connection);
    }
    //查询时关闭资源
    public static void closeResource(Statement statement,Connection connection,ResultSet resultSet){
        //先关闭ResultSet
        closeResultSet(resultSet);
        //再关闭Statement对象
        closeStatement(statement);
        //最后关闭Connection对象
        closeConnection(connection);
    }
    
}
  • Statement的使用

Statement接口特点:
用于执行静态 SQL 语句并返回它所生成结果的对象。 由
createStatement 创建,用于发送简单的 SQL 语句(不支持动态绑
定)。
注意
由于Statement对象是一个执行静态SQL语句的对象,所以该对 象存在SQL注入风险
因为sql和值放在一起构成一个字符串然后交给Statement 来执行
可以用Connection对象获取JDBC中三种Statement对象
  1. Statement:用于执行静态 SQL 语句。
  2. PreparedStatement:用于执行预编译SQL语句。
  3. CallableStatement:用于执行数据库存储过程。
  • 通过Statement 添加数据

创建表
数据库创建
数据库JDBC编写代码的结构是固化的
1.try catch 语句不能再向上抛,会引起两个代码 解耦合导致数据库异常
2.获取连接:
因为还要关闭它,所以要放在try— catch外面定义Connection
3.获取能够执行sql语句的Statement对象:
因为还要关闭它,所以要放在try— catch外面定义Statement
4.在拿到这个statement对象后,就要通过这个对象的API来完成sql语句的执行
statement.execute() 
返回一个布尔类型的值,他能够返回一个result set,就返回一个true,如果不能返回结果集,而是完成了一个数据更新,就返回false
eg: statement.executeupdate()
专门完成一个DML操作的,返回一个int,表示在添加,修改,更新后在数据库当中所受影响的数据的条数,
如果是查询的话,就调用 statement.executeQuery() 
因为是完成添加用户,可以用statement.execute() ,也可以用statement.executeupdate()
5.这个()里需要一个String类型的sql语句(需要执行的):
因为没有指定列,所以按照创建的表的列的顺序添加,第一个参数是主键自增长,有没有写列,所以要用default来占位
'  '  在SQl语句中表示字符串类型,但我的username是变量,我需要将值从变量中提取出来,“+username+”  拼接到语句里
最后形成了‘ “+username+ ” ’  作为第二个参数  
String sql ="insert into users values(default ,‘"+username+"’,"+userage+")";  
因为是静态输入的SQl语句,所以所有的参数都需要手动拼接
6.一定要将创建的对象关掉,否则一直累积在内存中,会造成内存溢出
用创建的工具类
package com.itbaizhan;
import org.omg.IOP.ExceptionDetailMessage;
import java.sql.Connection;
import java.sql.Statement;
/**
 * Statement 对象的使用
 */
public class StatementTest {
    /**
     * 添加用户
     */
    public void insertUsers(String username ,int userage){
        //获取连接
        Connection connection =null;
        Statement statement=null;
        try{
            //获取connection对象
            connection =JdbcUtils.getConnect();
            //获取能够执行sql语句的Statement对象
            statement= connection.createStatement();
            //返回一个布尔类型的值,他能够返回一个result set
            //就返回个true,
            // 如果不能返回结果集,而是完成了一个数据更新
            //就返回false
            //定义需要执行的sql雨具
            String sql ="insert into users values(default ,'"+username+"',"+userage+")";
            //执行sql,返回一个boolean值
            boolean execute=statement.execute(sql);
            System.out.println(execute);
            //这样就完成了一个insert操作
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            JdbcUtils.closeResource(statement,connection);
        }
    }
}
7.再创建一个测试类test来测试一下这个方式能否完成用户的添加
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.Statement;
public class Test {
    public static void main(String[] args) {
        StatementTest st=new StatementTest();
        st.insertUsers("old",28);
    }
}
创建表要在itbz库里创建
copy完库要刷新才行
注意:引号的中英区别
  •  Statement修改用户信息

写更新语句或删除语句的时候一定不要忘记where条件,否则会影响整个表中数据
注意:空格
   /**
     * 修改用户信息
     */
    public void updateUsers(int userid ,String username,int userage){
        Connection connection=null;
        Statement statement=null;
        try{
            //获取连接对象
            connection=JdbcUtils.getConnect();
            //获取Statement对象
            statement=connection.createStatement();
            //定义sql语句
            String sql="update users set username='"+username+"', userage="+userage+" where userid="+userid;
            //执行sql语句
            int i= statement.executeUpdate(sql);
            System.out.println(i);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(statement,connection);
        }
    }
测试:
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.Statement;
public class Test {
    public static void main(String[] args) {
        StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
        st.updateUsers(1,"tangan",19);
    }
}
返回的值不需要的话可以不要将他打印出来
  • 删除数据

    public void deleteUsersById(int userid){
        Connection connection=null;
        Statement statement=null;
        try{
            //.获取数据库连接
            connection=JdbcUtils.getConnect();
            // 获取Statement对象
            statement=connection.createStatement();
            //定义执行删除的语句
            String sql ="delete from users where userid="+userid;
            //执行sql
            int i= statement.executeUpdate(sql);
            System.out.println(i);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(statement,connection);
        }
    }
测试:
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.Statement;
public class Test {
    public static void main(String[] args) {
        StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
       // st.updateUsers(1,"tangan",19);
        st.deleteUsersById(2);
    }
}

PreparedStatement对象简介(重点):

继承自 Statement 接口,由 preparedStatement方法创建。PreparedStatement具有预编译SQL语句能力,所以PreparedStatement 对象比 Statement 对象的效率更高,由于实现了动态的参数绑定,所以可以防止 SQL 注入,所以我们一般都使用 PreparedStatement。

PreparedStatement对象的特点:

  1. PreparedStatement 接口继承 Statement 接口

  2. PreparedStatement 效率高于 Statement

  3. PreparedStatement 支持动态绑定参数

  4. PreparedStatement 具备 SQL 语句预编译能力

  5. 使用 PreparedStatement 可防止出现 SQL 注入问题

PreparedStatement 的预编译能力:

语句的执行步骤:
  1. 语法和语义解析
  2. 优化 sql 语句,制定执行计划
  3. 执行并返回结果
但是很多情况,我们的一条 sql 语句可能会反复执行,或者每次执行的时候只有个别的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值同)。 如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行 了。 所谓预编译语句就是将这类语句中的值用占位符 替代,可以视为将 sql 语句模板化或者说参数化预编译语句的优势 在于:一次编译、多次运行,省去了解析优化等过程;此外预编译 语 句能防止 sql 注入
通过PrepareStatement 对象介绍:preparedStatement 先是对sql语法进行判断如果语句的结构没有问题就交给语义解析器优化器结合语句特点生成一个执行计划重要的是他会缓存这个执行计划,下次再输入相同的Sql语句就不需进行语法和语义的解析以及优化,直接调用与之对应的执行计划去执行就好了如果用statemet的话,它是将结构和值作为整体一条数据,是不会缓存的而PrepareStatement就将SQL语句和值分离,可以缓存SQL语句只有在相同的Connection ,相同的sql 语句下,值不同才会有效
  • Preparement 添加数据

Sql语句里用?占位(即便是字符串类型)?是PreparedStatement对象中的绑定参数的占位符。问号的位置是从1开始计数
PreparedStatement 是Statement的子接口
因为已经在try-catch 语句外边定义了类型,所以对象前面不用再加类型
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
 * PreparedStatement使用的测试类
 */
public class PreparedStatementTest {
    /**
     *添加用户
     */
    public void insertUsers(String username ,int userage){
        Connection connection =null;
        PreparedStatement ps =null;
        try{
            //获取数据库连接
            connection=JdbcUtils.getConnect();
            //执行Sql语句
            String  sql = "insert into users values(default,?,?)";
            //创建PreparedStatement对象
            ps= connection.prepareStatement(sql);
            //完成参数的绑定
            ps.setString(1,username);
            ps.setInt(2,userage);
            int i= ps.executeUpdate();
            System.out.println(i);
        }catch(Exception e ){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
}
test测试:
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.Statement;
public class Test {
    public static void main(String[] args) {
       // StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
       // st.updateUsers(1,"tangan",19);
      //  st.deleteUsersById(2);
        PreparedStatementTest pt=new PreparedStatementTest();
        pt.insertUsers("oldlu",38);
    }
}
  • 更新数据

 /**
     * 根据用户ID修改用户姓名与年龄
     */
    public void updateUserById (int userid,String username,int userage){
        Connection connection=null;
        PreparedStatement ps =null;
        try{
            //获取数据库连接对象
            connection = JdbcUtils.getConnect();
            String sql = "update users set username = ? , userage=? where userid=? ";
            //创建PreparedStatement对象
            ps=connection.prepareStatement(sql);
            //参数绑定
            ps.setString(1,username);
            ps.setInt(2,userage);
            ps.setInt(3,userid);
            int i =ps.executeUpdate();
            System.out.println(i);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
  /**
     * 根据用户ID修改用户姓名与年龄
     */
    public void updateUserById (int userid,String username,int userage){
        Connection connection=null;
        PreparedStatement ps =null;
        try{
            //获取数据库连接对象
            connection = JdbcUtils.getConnect();
            String sql = "update users set username = ? , userage=? where userid=? ";
            //创建PreparedStatement对象
            ps=connection.prepareStatement(sql);
            //参数绑定
            ps.setString(1,username);
            ps.setInt(2,userage);
            ps.setInt(3,userid);
            int i =ps.executeUpdate();
            System.out.println(i);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
test:
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.Statement;
public class Test {
    public static void main(String[] args) {
       // StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
       // st.updateUsers(1,"tangan",19);
      //  st.deleteUsersById(2);
        PreparedStatementTest pt=new PreparedStatementTest();
        //pt.insertUsers("oldlu",38);
        pt.updateUserById(3,"kevin",21);
    }
}
  • 删除数据

  /**
     * 根据用户ID删除指定用户
     */
    public void deleteUsersById(int userid){
        Connection connection=null;
        PreparedStatement ps=null;
        try{
            //获取数据库连接对象
            connection=JdbcUtils.getConnect();
            String sql="delete from users where userid=?";
            ps=connection.prepareStatement(sql);
            //绑定参数
            ps.setInt(1,userid);
            int i=ps.executeUpdate();
            System.out.println(i);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
test:
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.Statement;
public class Test {
    public static void main(String[] args) {
       // StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
       // st.updateUsers(1,"tangan",19);
      //  st.deleteUsersById(2);
        PreparedStatementTest pt=new PreparedStatementTest();
        //pt.insertUsers("oldlu",38);
        //pt.updateUserById(3,"kevin",21);
        pt.deleteUsersById(3);
    }
}
  • ResultSet

ResultSet接口的特点:

ResultSet用来存放数据库查询操作获得结果集,通过对ResultSet
的操作可以获取查询到的结果集数据。
ResultSet 对象中存放的并不是我们查询到的所有的结果集。它
采用分块加载的方式来载入结果集数据。

ResultSet特点:

1.ResultSet 对象具有指向其当前数据行的指针。最初,指针被置于第一行之前。next 方法将指针移
动到下一行;因为该方法在 ResultSet 对象中没有下一行时返回 false,所以可以在 while 循环中使
用它来迭代结果集。
2.默认的 ResultSet 对象仅有一个向前移动的指针。因此,只能迭代它一次,并且只能按从第一行到
最后一行的顺序进行。
3.ResultSet 接口提供用于获取当前行检索列值的获取方法(getBoolean、getLong 等)。可以使用
列的索引位置或列的名称检索值。
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.*;
/**
 * 获取结果集测试类
 */
public class ResultSetTest {
    /**
     * 查询所有用户
     */
    public void selectUsersAll(){
        Connection connection =null;
        PreparedStatement ps =null;
        ResultSet resultSet=null;
        try{
            //获取数据库连接
            connection=JdbcUtils.getConnect();
            String sql="select * from users ";
            ps=connection.prepareStatement(sql);
            //执行查询
            resultSet=ps.executeQuery();
            //操作ResultSet对象获取查询的结果集
            while(resultSet.next()){
                //获取列的数据
                int userid=resultSet.getInt("userid");//返回了第一个单元格的数据
                String username=resultSet.getString("username");
                int userage=resultSet.getInt("userage");
                System.out.println(userid+" "+ username+" "+userage);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            JdbcUtils.closeResource(resultSet,ps,connection);
        }
    }
}
test:
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
public class Test {
    public static void main(String[] args) {
       // StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
       // st.updateUsers(1,"tangan",19);
      //  st.deleteUsersById(2);
       // PreparedStatementTest pt=new PreparedStatementTest();
        //pt.insertUsers("oldlu",38);
        //pt.updateUserById(3,"kevin",21);
        // pt.deleteUsersById(3);
        ResultSetTest rt =new ResultSetTest();
        rt.selectUsersAll();
    }
}
  • ORM编程思想

ORM简介:

对象关系映射(英语:Object Relational Mapping,简称ORM,或
O/R mapping)是一种为了解决面向对象语言与关系数据库存在的
互不匹配的现象
实体类(存储类):
实体类就是一个定义了属性,拥有getter、setter、无参构造方法
(基本必备)的一个类。实体类可以在数据传输过程中对数据进行
封装,相当于一个“工具”、“容器”、“载体”,能存储、传输数据,能
管理数据
处理数据的叫(过程类)之前写的都叫过程类
实体类特点:
1 实体类名,尽量和数据库中的表名一一对应
2 实体类中的属性对应数据库表中的字段,相关的命名最好也一一对应
3 实体类内方法主要有,getter、setter方法,用于设置、获取数据
4 实体类属性一般为private类型,方法为public类型
5 实体类应该有,无参、有参构造方法(随手添加一个无参构造方法,在创建对象的时候更加灵活,而且以后会学到ORM的一些高级框架会要求必须有无参构造方法)
  • ORM使用

现在我们还是来手动映射!
将查询到的数据有效的管理起来!
Users实体类
因为每查询到一条数据,存到一个User类里,所以应该在while 循环里实例化。但如果是主键或者唯一性约束的就可以放在while循环外面定义。如果是返回多条,一定是在while循环里定义的。
每次实例化的对象要保存,否则就会被覆盖。于是就放在一个集合里,集合要在循环的外边创建
再将结果集改造。
按照之前的代码添加的话,那么没有返回值,改方法后就谁调用这个方法谁就会获得所有用户的信息。
原理:将对象映射到Users类里,再将对象放进集合里,再返回集合,最后遍历该容器
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
 * 获取结果集测试类
 */
public class ResultSetTest {
    /**
     * 查询所有用户
     */
    public List<Users> selectUsersAll(){
        Connection connection =null;
        PreparedStatement ps =null;
        ResultSet resultSet=null;
        List<Users> list =new ArrayList<>();
        try{
            //获取数据库连接
            connection=JdbcUtils.getConnect();
            String sql="select * from users ";
            ps=connection.prepareStatement(sql);
            //执行查询
            resultSet=ps.executeQuery();
            //操作ResultSet对象获取查询的结果集
            while(resultSet.next()){
                //获取列的数据
                int userid=resultSet.getInt("userid");//返回了第一个单元格的数据
                String username=resultSet.getString("username");
                int userage=resultSet.getInt("userage");
               // System.out.println(userid+" "+ username+" "+userage);
                //ORM映射处理
                Users users =new Users();
                //将取到的数据放到users对象的那3个属性里
                users.setUserid(userid);
                users.setUsername(username);
                users.setUserage(userage);
                list.add(users);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            JdbcUtils.closeResource(resultSet,ps,connection);
        }
        return list;
    }
}
test:
package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;
public class Test {
    public static void main(String[] args) {
       // StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
       // st.updateUsers(1,"tangan",19);
      //  st.deleteUsersById(2);
       // PreparedStatementTest pt=new PreparedStatementTest();
        //pt.insertUsers("oldlu",38);
        //pt.updateUserById(3,"kevin",21);
        // pt.deleteUsersById(3);
        ResultSetTest rt =new ResultSetTest();
        //rt.selectUsersAll();
        //遍历
        List<Users>list =rt.selectUsersAll();
        for (Users users:list){
            System.out.println(users.getUserid()+ " "+ users.getUsername()+" "+ users.getUserage());
        }
    }
}
  • Sql注入

package com.itbaizhan;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
/**
 * sql注入测试类
 */
public class SqlInjectTest {
    /**
     * 体现sql注入
     */
    public void sqlInject(String username ,int userage){
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;
        try{
           //获取连接
           connection=JdbcUtils.getConnect();
           //创建Statement对象
            statement=connection.createStatement();
            //定义sql语句
            String sql="select * from users where username='"+username+"'and userage="+userage;
            System.out.println(sql);
            //执行sql语句
            resultSet=statement.executeQuery(sql);
            //处理结果集
            while(resultSet.next()){
                int userid=resultSet.getInt("userid");
                String name =resultSet.getString("username");
                int age= resultSet.getInt("userage");
                System.out.println(userid+" "+name+" "+age);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            JdbcUtils.closeResource(resultSet,statement,connection);
        }
    }
    public static void main(String[] args) {
        SqlInjectTest sit=new SqlInjectTest();
        sit.sqlInject("tangan",19 );
    }
}

问题:SQL注入:

 public static void main(String[] args) {
        SqlInjectTest sit=new SqlInjectTest ();
        sit.sqlInject(“tangan'or 1=1 -- ”,19 );
    }
结果:
#‘单引号与前半部分构成一个整体,1=1是必然成立的条件 
select * from users where username='tangan'or 1=1 -- 'and userage=19  
“ -- ” 后面是注释部分,相当于Sql语句为:
select * from users where username='tangan'or 1=1 
查username 为tangan 以及所有的数据 
1 tangan 19
2 oldlu 38
  • 解决sql 注入

用PreparedStatement
 public void noSqlInject(String username,int userage){
        Connection connection =null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try{
            //获取连接
            connection=JdbcUtils.getConnect();
            //创建preparedStatement对象
            ps=connection.prepareStatement("select * from users where username=? and userage =?");
            //绑定参数
            ps.setString(1,username);
            ps.setInt(2,userage);
            //执行SQL
            rs=ps.executeQuery();
            //参数绑定
            while(rs.next()){
                int userid =rs.getInt("userid");
                String name =rs.getString("username");
                int age=rs.getInt("userage");
                System.out.println(userid+" "+name+" "+age  );
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(rs,ps,connection);
        }
    }
test:
public static void main(String[] args) {
        SqlInjectTest sit=new SqlInjectTest();
        sit.sqlInject("tangan'or 1=1 -- ",19 );
        System.out.println("******************************************");
        sit.noSqlInject("tangan'or 1=1 -- ",19);
    }
没有输出结果
  •  批量添加数据简介

在JDBC中通过PreparedStatement的对象的addBatch()和executeBatch()方法进行数据的批量插入。
  1. addBatch()把若干SQL语句装载到一起,然后一次性传送到数据库执行,即是批量处理sql数据的。
  2. executeBatch()会将装载到一起的SQL语句执行。
注意:
MySql默认情况下是不开启批处理的。
数据库驱动从5.1.13开始添加了一个对rewriteBatchStatement的参数的处理,该参数能够让MySql开启批处理。
在url中添加 该参数:rewriteBatchedStatements=true
参数:
#连接mysql数据库的URL
url = jdbc:mysql://localhost:3306/itbz?useSSL=false&userUnicode=true&characterEncoding=utf-8
#连接数据库的用户名
name =root
#连接数据库的密码
pwd= root
#数据库驱动名称
driver=com.mysql.jdbc.Driver
  • 数据的批量添加

ps.executeBatch();  返回值会出现正数,表示更新的条数,出现负数,表示不知道更新的数据条数,但都表示批量操作成功

修改配置

#连接mysql数据库的URL
url = jdbc:mysql://localhost:3306/itbz?useSSL=false&rewriteBatchedStatements=true
#连接数据库的用户名
名称 =根
#连接数据库的密码
pwd= 根
#数据库驱动名称
驱动程序=com.mysql.jdbc.Driver
缓存,否则交互次数过多,效率低
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
 * 向mysql 数据库批量添加数据测试类
 */
public class AddBatchTest {
    /**
     * 批量添加数据方法1:
     */
    public void addBatch1(){
        Connection connection=null;
        PreparedStatement ps=null;
        try {
           //创建连接
           connection=JdbcUtils.getConnect();
           //创建PreparedStatement
            ps=connection.prepareStatement("insert into users values(default,?,?)");
            //绑定参数
            for (int i=0;i<1000;i++){
                //绑定username
                ps.setString(1,"ITBZ"+i);
                //绑定userage
                ps.setInt(2,20);
                //缓存sql
                ps.addBatch();
            }
            //执行sql
            ps.executeBatch();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
    public static void main(String[] args) {
        AddBatchTest addBatchTest= new AddBatchTest();
        addBatchTest.addBatch1();
    }
}
注意:缓存量过大也是不适合一次性缓存到本地的内存中,会造成内存泄漏记得清除缓存,适用于数据量非常大的
/**
     * 批量添加数据方法2
     */
    public void addBatch2(){
        Connection connection=null;
        PreparedStatement ps=null;
        try {
            //创建连接
            connection=JdbcUtils.getConnect();
            //创建PreparedStatement
            ps=connection.prepareStatement("insert into users values(default,?,?)");
            //绑定参数
            for (int i=0;i<2000;i++){
                //绑定username
                ps.setString(1,"ITBZ"+i);
                //绑定userage
                ps.setInt(2,20);
                //缓存sql
                ps.addBatch();
                //每500插入一次
                if (i%500 == 0){
                    //执行sql
                    ps.executeBatch();
                    //清除缓存
                    ps.clearBatch();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
i% 500 ==  0  取模为0 说明是偶数,每500个偶数存一次,i<1000,所以不会存起来
  • JDBC事务

1.事务简介

        1.事务:
事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地
执行,要么完全地不执行。
        2.事务操作流程:
开启事务
提交事务
回滚事务

2.JDBC中事务处理特点:

在JDBC中,使用Connection对象来管理事务,默认为自动提交事务。可以通过setAutoCommit(boolean autoCommit)方法设置事务是否自动提交,参数为boolean类型,默认值为true,表示自动提交事务,如果值为false则表示不自动提交事务,需要通过commit方法手动提交事务或者通过rollback方法回滚事务
  • JDBC事务的实现

先设置为手动最后提交
 /**
     * 批量添加数据方法2
     */
    public void addBatch2(){
        Connection connection=null;
        PreparedStatement ps=null;
        try {
            //创建连接
            connection=JdbcUtils.getConnect();
            //设置事物的提交方式,将自动提交改为手动提交
            connection.setAutoCommit(false);
            //创建PreparedStatement
            ps=connection.prepareStatement("insert into users values(default,?,?)");
            //绑定参数
            for (int i=0;i<1500;i++){
                //绑定username
                ps.setString(1,"ITBZ"+i);
                //绑定userage
                ps.setInt(2,20);
                //缓存sql
                ps.addBatch();
                //每500插入一次
                if (i%500 == 0){
                    //执行sql
                    ps.executeBatch();
                    //清除缓存
                    ps.clearBatch();
                }
            }
            //提交书屋
            connection.commit();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
出现异常还要回滚
 public void addBatch2(){
        Connection connection=null;
        PreparedStatement ps=null;
        try {
            //创建连接
            connection=JdbcUtils.getConnect();
            //设置事物的提交方式,将自动提交改为手动提交
            connection.setAutoCommit(false);
            //创建PreparedStatement
            ps=connection.prepareStatement("insert into users values(default,?,?)");
            //绑定参数
            for (int i=0;i<1500;i++){
                //绑定username
                ps.setString(1,"ITBZ"+i);
                //绑定userage
                ps.setInt(2,20);
                //缓存sql
                ps.addBatch();
                //每500插入一次
                if (i%500 == 0){
                    //执行sql
                    ps.executeBatch();
                    //清除缓存
                    ps.clearBatch();
                }
            }
            //提交书屋
            connection.commit();
        }catch(Exception e){
            e.printStackTrace();
            //回滚事务
            JdbcUtils.rollback(connection);
        }finally{
            JdbcUtils.closeResource(ps,connection);
        }
    }
  •  模糊查询

1.like 里的通配直接用问号,最后参数绑定的时候才用% 表示左通配还是右通配,还是两端通配,因为%不是sql语句的一部分,而是条件的一部分
2.setString 方法可以将字符串类型的参数直接加上两个单引号绑定拼接
3.ps.setString(1,"%"+username+"%");【也不太好】因为这就将内容写死了,最好应该是ps.setString(1,username);在给定具体值的时候再决定在哪通配
4.like查询一定会返回多条数据,所以要用while 
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
 * 模糊查询测试类
 */
public class FuzzyQueryTest {
    /**
     * 根据用户名称模糊查询用户信息
     */
    public List<Users> fuzzyQuery(String username){
        //创建一个list对象
        List<Users> list =new ArrayList<>();
        Connection connection=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try{
            //获取数据库连接
            connection=JdbcUtils.getConnect();
            //创建PreparedStatement对象
            ps=connection.prepareStatement("select * from users where username  like ? ");
            //参数绑定
            ps.setString(1,username);
            //执行sql语句
            rs=ps.executeQuery();
            while (rs.next()){
                //将每条查询出来的数据放在user里作为一个单独的对象
                Users user=new Users();
                user.setUserid(rs.getInt("userid"));
                user.setUsername(rs.getString("username"));
                user.setUserage(rs.getInt("userage"));
                //再将创建出来的对象放进list容器里
                list.add(user);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(rs,ps,connection);
        }
        //返回列表
        return list;
    }
    public static void main(String[] args) {
        //将这个类实例化
        FuzzyQueryTest ft =new FuzzyQueryTest();
        List<Users> users=ft.fuzzyQuery("%d%");
        //遍历这个list容器
        for(Users user1:users){
            System.out.println(user1.getUserid()+" "+user1.getUsername()+" " + user1.getUserage());        }
    }
}
  • 动态条件查询

根据用户给定的条件来决定执行什么样的查询:
1.之所以用list类型来定义这个方法,是因为动态查询的结果不止一个
2.之所以要用Users users作为参数,是应为未来要把查询的这个条件放到这个users对象的属性当中来传递
因为有可能是有条件,有可能是没条件,至于多条件,则依赖于个users对象的属性来存放
SQL语句也是不确定的,因为查询的条件要根据users 对象的属性有哪些来判断,所以要拼语句
3.将拼接语句凡在另一个方法里面,好处是如果这个类里面有其他的方法要用到sql语句的拼接就方便多了,且结构清晰
4.因为只为这个类服务,所以可将这个方法设置为private 
5.用StringBuilder 来做字符串的拼接
6.前面的投影部分相同只是where 条件不同
注意:只有在ps.setString(1,username);参数绑定 里字符串类型不用加单引号,其他方法里都要加
7.分别对参数判断符合后拼接进SQL语句里,因为如果第一个userid 不满足条件,那么将会直接将and拼接到where后面,明显不行,那么解决方法就是用1=1 的方法解决拼接格式问题
8. 1=1 就是select * 的意思
注意:append双引号中and前面一定要加空格,不然容易与上个语句连在一起
9.最后用toString方法
10.查所有数据就是queryUsers里直接放users对象,不给users对象添加属性
  public static void main(String[] args) {
        DynamicConditionQueryTest dt=new DynamicConditionQueryTest();
        Users users=new Users();
        List<Users> list =dt.queryUsers(users);
        for(Users user2: list){
            System.out.println(user2.getUserid()+" "+user2.getUsername()+" "+ user2.getUserage());
        }
    }
}
而添加属性
package com.itbaizhan;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
 * 动态查询测试类
 */
public class DynamicConditionQueryTest {
    /**
     * 动态查询Users
     */
    public List<Users> queryUsers(Users users) {
            //创建一个list对象
            List<Users> list = new ArrayList<>();
            Connection connection = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                //获取数据库连接
                connection = JdbcUtils.getConnect();
                //拼接查询sql语句
                String sql = this.generateSql(users);
                //创建PreparedStatement对象
                ps = connection.prepareStatement(sql);
                //执行sql语句
                rs = ps.executeQuery();
                while (rs.next()) {
                    //将每条查询出来的数据放在user里作为一个单独的对象
                    Users user = new Users();
                    user.setUserid(rs.getInt("userid"));
                    user.setUsername(rs.getString("username"));
                    user.setUserage(rs.getInt("userage"));
                    //再将创建出来的对象放进list容器里
                    list.add(user);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.closeResource(rs, ps, connection);
            }
            //返回列表
            return list;
        }
    /**
     * 生成动态查询sql
     */
    private  String generateSql(Users users) {
        StringBuffer sb = new StringBuffer("select * from users where 1=1 ");
        if (users.getUserid() > 0) {
            sb.append(" and userid = ").append(users.getUserid());
        }
        if (users.getUsername() != null && users.getUsername().length() > 0) {
            sb.append(" and username = '").append(users.getUsername()).append("'");
        }
        if (users.getUserage()>0){
            sb.append(" and userage = ").append(users.getUserage());
        }
        return sb.toString() ;
    }
    public static void main(String[] args) {
        DynamicConditionQueryTest dt=new DynamicConditionQueryTest();
        Users users=new Users();
        users.setUsername("oldli");
        List<Users> list =dt.queryUsers(users);
        for(Users user2: list){
            System.out.println(user2.getUserid()+" "+user2.getUsername()+" "+ user2.getUserage());
        }
    }
}
当mysql语句出错的时候,可以将语句打印出来,判断错在哪
  • 分页查询

要多少数据,差多少数据,大大减少数据库服务器的内存消耗
分页查询分类:
1.物理分页:要多少查多少(主要)
在数据库执行查询时(实现分页查询),查询需要的数据—依赖数据库的SQL语句
在SQL查询时,从数据库只检索分页需要的数据
通常不同的数据库有着不同的物理分页语句
MySql物理分页采用limit关键字
2.逻辑分页:(仍存在内存溢出的复方鲜)
在sql查询时,先从数据库检索出所有数据的结果集,在程序内,通过逻辑语句获得分页需要的数

问题:
如何在MySql中实现物理分页查询?

解决方法:

使用limit方式。
limit的使用:
select * from tableName limit m,n
其中m与n为数字。n代表需要获取多少行的数据项,而m代表从哪开始(以0为起始)。
必须要是double类型数才能进行该方法,得到的数强转为int类型
检查时就检查结果集有没有放进page里,总条数有没有放到page里,总页数有没有放到page里
page
package com.itbaizhan;
import java.util.List;
/**
 * 分页查询实体类
 */
public class Page<T> {
    //当前页
    private int currentPage;
    //每页显示的条数
    private int pageSize;
    //总页数
    private  int totalCount;
    //总页数
    private int totalPage;
    //结果集
    private List<T> result;
    public int getCurrentPage() {
        return currentPage;
    }
    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }
    public int getPageSize() {
        return pageSize;
    }
    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public int getTotalCount() {
        return totalCount;
    }
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }
    public int getTotalPage() {
        return totalPage;
    }
    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }
    public List<T> getResult() {
        return result;
    }
    public void setResult(List<T> result) {
        this.result = result;
    }
}
pageTest
package com.itbaizhan;
import javax.imageio.stream.ImageInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
 * 分页查询测试类
 */
public class PageTest {
    /**
     * 分页查询Users
     */
    public Page<Users> selectPage(Page page){
        Connection connection=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        List<Users> list=new ArrayList<>();
        try{
            connection=JdbcUtils.getConnect();
            ps=connection.prepareStatement("select * from users limit ?,?");
            //绑定m值
            ps.setInt(1,(page.getCurrentPage()-1)*page.getPageSize());
            //绑定n值
            ps.setInt(2,page.getPageSize());
            //执行查询
            rs=ps.executeQuery();
            //处理结果集
            while(rs.next()){
                //完成ORM映射
                Users users= new Users();
                users.setUserid(rs.getInt("userid"));
                users.setUsername(rs.getString("username"));
                users.setUserage(rs.getInt("userage"));
                list.add(users);
            }
            //将结果集存放到Page对象中
            page.setResult(list);
            //查询总条数
            ps=connection.prepareStatement("select count(*) from users");
            //执行查询
            rs=ps.executeQuery();
            while(rs.next()){
               int count = rs.getInt(1);
                //保存总条数
                page.setTotalCount(count);
                //换算总页数=总条数/每页显示的条数  向上取整
                int totalPage=(int)Math.ceil(1.0*count/page.getPageSize());
                //保存总页数
                page.setTotalPage(totalPage);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.closeResource(rs,ps,connection);
        }
        return page;
    }
    public static void main(String[] args) {
        PageTest pt=new PageTest();
        Page page=new Page();
        page.setCurrentPage(1);
        page.setPageSize(2);
        Page page1=pt.selectPage(page);
        System.out.println("总条数:"+page1.getTotalCount());
        System.out.println("总页数:"+page1.getTotalPage());
        System.out.println("当前页:"+page1.getCurrentPage());
        System.out.println("每页显示的条数:"+page1.getPageSize());
        List<Users> list =page1.getResult();
        for (Users user: list){
            System.out.println(user.getUserid()+" "+ user.getUsername()+" "+user.getUserage() );
        }
    }
}

连接数据库:

 1.直连 现用现创建Connection对象,用完关闭
 缺点:效率低(TCP三次握手,)
 2.池连: 什么是数据库连接池?
数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放(用的时候从池里拿,用完还回去)
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

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

1.普通的JDBC数据库连接使用 DriverManager 来获取,每次向数
据库建立连接的时候都要将 Connection加载到内存中,再验证
用户名和密码,所以整个过程比较耗时。
2.需要数据库连接的时候,就向数据库要求一个,执行完成后再断
开连接。这样的方式将会消耗大量的资源和时间。数据库的连接
资源并没有得到很好的重复利用。若同时有几百人甚至几千人在
线,频繁的进行数据库连接操作将占用很多的系统资源,严重的
甚至会造成服务器的崩溃。
3.对于每一次数据库连接,使用完后都得断开。否则,如果程序出
现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将
导致重启数据库

JDBC数据库连接池的必要性:

1·.数据库连接池的基本思想:为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连
接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
2.数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连
接,而不是重新建立一个。
3.数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

数据库连接池的优点:

1 资源重用:由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
2 更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
3 新的资源分配手段:对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置实现某一应用最大可用数据库连接数的限制避免某一应用独占所有的数据库资源.
4 统一的连接管理:避免数据库连接泄露在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。

常用的数据库连接池:

1.c3p0:是一个开源组织提供的数据库连接池,速度相对较慢,稳定性还可以。
2.DBCP:是Apache提供的数据库连接池。速度相对c3p0较快,但自身存在bug。
3.Druid:是阿里提供的数据库连接池,据说是集DBCP、c3p0优点于一身的数据库连接池,目前经常使用。
  • Druid简介

将jar包拷贝到lib 文件夹里,还需要  add as library 才能导进项目中:

Druid使用步骤:

1.导入druid-1.2.8.jar包到lib目录下,并引入到项目中
2.在src下创建一个druid.properties类型的文件,并写入
3.加载配置文件
4.获取连接池对象
        在java.sql 下的接口
5.通过连接池对象获取连接
DruidTest.class.getClassLoader()获得类加载器.getResourceAsStream("")加载什么配置文件,返回一个IO流,接收一下
Properties的包要导对了 import java.util.Properties;
pos.load(inputStream);   有异常,需要抛出
DataSource  ds= DruidDataSourceFactory .createDataSource(pos);有异常要抛出  ,所以直接抛Exception
ds.getConnection();返回一个Connection对象druid.properties
url=jdbc:mysql://localhost:3306/itbz?useSSL=false
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
initialSize=10
maxActive=20
druidTest:
package com.itbaizhan;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
/**
 * Durid连接池测试类
 */
public class DruidTest {
    public static void main(String[] args) throws Exception {
        //获取读取druid配置文件的字节输入流
        InputStream inputStream=DruidTest.class.getClassLoader().getResourceAsStream("druid.properties");
        //创建Properties对象
        Properties pos=new Properties();
        //加载配置文件
        pos.load(inputStream);
        //获取连接池对象
        DataSource  ds= DruidDataSourceFactory.createDataSource(pos);
        //获取连接
        Connection connection=ds.getConnection();
        System.out.println(connection);
    }
}
  • druid 封装工具类

dataSource只有 一个,所以放在Static 即可
  • 应用程序分层

1.应用程序分层简介:
应用程序分层是指通过创建不同的包来实现项目的分层,将项目中
的代码根据功能做具体划分,并存放在不同的包下。
2.三层结构:
三层结构就是将整个业务应用划分为:表述层、业务逻辑层 、数据
访问层。区分层次的目的即为了“高内 聚低耦合”的思想。在软件体
系架构设计中,分层式结构是最常见,也是最重要的一种结构。
3.层与层之间要松耦合,有利于代码的维护
4.在写介于Jdbc操作数据库的时候,要求用trycatch 而不是抛出异常,catch 是为了防止出现sql.Exception 异常,如果不在数据访问层catch掉这个异常,将会抛到业务逻辑层,业务逻辑层拿到了数据访问层的异常,造成层与层之间紧耦合现象。所以如果数据访问层真的出现了异常,还要通过信息告诉业务逻辑层,可以在catch里抛用户自定义异常,这样渗透到业务逻辑层里的只是用户自定义异常,不是数据访问层的异常,解决二者异常
分层优点:
1.分层结构将应用系统划分为若干层,每一层只解决问题的一部
分,通过各层的协作提供整体解决方案。大的问题被分解为一系
列相对独立的子问题,局部化在每一层中,这样就有效的降低了
单个问题的规模和复杂度,实现了复杂系统的第一步也是最为关
键的一步分解。
2.分层结构具有良好的可扩展性,为应用系统的演化增长提供了一
个灵活的支持,具有良好的可扩展性。增加新的功能时,无须对
现有的代码做修改,业务逻辑可以得到最大限度的重用。
3.分层结构易于维护。在对系统进行分解后,不同的功能被封装在
不同的层中,层与层之间的耦合显著降低。因此在修改某个层的
代码时,只要不涉及层与层之间的接口,就不会对其他层造成严
重影响。
分层命名:
表述层:web或controller
业务层:service
数据访问层:dao (Data Access Object)

基于Driuid封装工具类:

package com.itbaizhan;
import com.mysql.jdbc.JDBC4PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collections;
import java.util.List;
public class Test {
    public static void main(String[] args) {
       // StatementTest st=new StatementTest();
     //   st.insertUsers("old",28);
       // st.updateUsers(1,"tangan",19);
      //  st.deleteUsersById(2);
       // PreparedStatementTest pt=new PreparedStatementTest();
        //pt.insertUsers("oldlu",38);
        //pt.updateUserById(3,"kevin",21);
        // pt.deleteUsersById(3);
//        ResultSetTest rt =new ResultSetTest();
//        //rt.selectUsersAll();
//        //遍历
//        List<Users>list =rt.selectUsersAll();
//        for (Users users:list){
//            System.out.println(users.getUserid()+ " "+ users.getUsername()+" "+ users.getUserage());
//        }
        Connection conn= JdbcDuridUtill.getConnection();
        System.out.println(conn);
    }
}
druid文件:
url=jdbc:mysql://localhost:3306/itbz?useSSL=false
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
initialSize=10
maxActive=20
}
问题一:
问题分析:

方法中的类型和你现在返回值的类型不一致

问题二:
这个方 法返回的不是Connection类型吗?
问题解决:
是Connection类型,但是不止一个包有这个类
删掉  import java.sql.Connection;  
  • 应用程序分层实现

  • 分层实现

1.创建lib目录,用于加载jar 类包
2.在实体类里重载toString方法
3.异常两种类型:
        1.运行时异常 
        2.非运行时异常(编译异常)
4. 创建相关包和类方法:
在表述层调用业务层代码,在业务层调用数据操作层或者叫持久层代码。
对于这个业务的实现编码过程当中,你的编码的顺序可以先写web 包,再写业务包,再写数据持久层,也可以乱着顺序写。我建议从后往前写即倒着写。
5.如果是操作的Users表,就要以表名作为前缀再加上Dao作为接口名

Statement 同理解决
import java.sql.PreparedStatement;
没有new Users是因为,如果相应的ID有Users就在循环里将其new出来,放里面就行了,如果没有while循环就不循环,new users就不执行。那么就会返回users=null; 查询的时候就方便判断有无users对象
数据层:
接口:


    package com.itbaizhan.dao;
    import com.itbaizhan.pojo.Users;
    public interface UsersDao {
        //接口里必须实现的方法,省略了public abstract
        /**
         * 根据用户ID查询用户
         */
        Users selectUsersById(int userid);
    }
实现类:
package com.itbaizhan.dao.impl;
import com.itbaizhan.JdbcDuridUtill;
import com.itbaizhan.dao.UsersDao;
import com.itbaizhan.exception.ApplicationException;
import com.itbaizhan.pojo.Users;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
/**
 * 接口实现类
 */
public class UsersDaoImpl implements UsersDao {
    /**
     * 根据用户ID查询用户
     * @param userid
     * @return
     */
    @Override
    public Users selectUsersById(int userid) {
        Connection connection= null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Users users=null;
        try{
            connection= JdbcDuridUtill.getConnection();
            ps=connection.prepareStatement("select * from users where userid = ?");
            ps.setInt(1,userid);
            rs= ps.executeQuery();
            while(rs.next()){
                //手动ORM映射
                users=new Users();
                users.setUserid(rs.getInt("userid"));
                users.setUsername(rs.getString("username"));
                users.setUserage(rs.getInt("userage"));
            }
        }catch(Exception e){
            e.printStackTrace();
            //抛出自定义异常信息,解决异常耦合问题
            throw new ApplicationException(e.getMessage());
        }finally{
            JdbcDuridUtill.closeResource(rs,ps,connection);
        }
        return users;
    }
}
exception 
Application
package com.itbaizhan.exception;
/**
 * 自定义异常,程序运行时异常
 */
public class ApplicationException extends RuntimeException {
    public ApplicationException() {
    }
    //实例化异常的时候传递信息
    public ApplicationException(String msg) {
        super(msg);
    }
    //除了传递异常信息,还可以保存异常
    public ApplicationException(String msg, Throwable throwable) {
    }
}
业务层:
在实例化接口实现类的时候类型用接口名:
在一个方法里如果你用到的是另一个对象的类型,那么两个对象就是依赖关系,存在紧耦合问题未来用Spring 框架解决依赖关系
好处:如果下次要添加功能就不需要改
UsersDao ud=new UserDaoImpl();
return null;
这部分代码,直接再写个接口实现类即可
以后都是在业务层做(异常)事务处理,而不是在数据持久层进行异常处理(有异常rollback,没异常commit)
接口
package com.itbaizhan.service;
import com.itbaizhan.pojo.Users;
public interface UsersService {
    Users findUsersById(int userid);
}
实现类
package com.itbaizhan.service.impl;
import com.itbaizhan.dao.UsersDao;
import com.itbaizhan.dao.impl.UsersDaoImpl;
import com.itbaizhan.pojo.Users;
import com.itbaizhan.service.UsersService;
public class UsersServiceImpl implements UsersService {
    /**
     * 根据用户ID查询用户业务
     * @param userid
     * @return
     */
    @Override
    public Users findUsersById(int userid) {
        UsersDao ud=new UsersDaoImpl();
        return ud.selectUsersById(userid);
    }
}
web层
没有web 组件,就把测试类作为一个外部层的视图,或者控制器的体现
package com.itbaizhan.web;
import com.itbaizhan.pojo.Users;
import com.itbaizhan.service.UsersService;
import com.itbaizhan.service.impl.UsersServiceImpl;
public class Test {
    public static void main(String[] args) {
        UsersService us= new UsersServiceImpl();
        Users u=us.findUsersById(1);
        System.out.println(u);
    }
}
  • 封装通用的DML操作
1.在这个分装后的方法里可以 添加,修改,删除数据
2.通用型的代码,一定是要抽出来的,作为接口放到外部
3.多个动态参数放到一个盒子里,所以定义个数组作为传递参数的盒子
4.用UseDao接口继承BaseDao 接口、用 userDaoImpl 类 继承BaseDaoImpl 类即可
5.绑定几个参数就看有几个参数在数组里
param[i]得对应参数,但位置为i+1
封装实现类
package com.itbaizhan.dao.impl;
/**
 * 通用接口实现类
 */
import com.itbaizhan.JdbcDruidUtill;
import com.itbaizhan.dao.BaseDao;
import com.itbaizhan.exception.ApplicationException;
import java.sql.*;
public class BaseDaoImpl implements BaseDao {
    /**
     * 通用DML操作方法
     * @param sql
     * @param param
     * @return
     */
    @Override
    public int executeUpdate(String sql, Object[] param) {
        Connection connection =null;
        PreparedStatement ps=null;
        //条数
        int row;
        try{
            connection=JdbcDruidUtill.getConnection();
            ps=connection.prepareStatement(sql);
            //绑定参数
            //得到参数个数
            ParameterMetaData pd=ps.getParameterMetaData();
            for(int i=0;i<pd.getParameterCount();i++){
                ps.setObject(i+1,param[i]);
            }
            //执行
            row=ps.executeUpdate();
        }catch(Exception e ){
            e.printStackTrace();
            throw new ApplicationException(e.getMessage());
        }finally{
            JdbcDruidUtill.closeResource(ps,connection);
        }
        return row;
    }
}

在接口里增加个方法
userdao接口
package com.itbaizhan.dao;
import com.itbaizhan.pojo.Users;
public interface UsersDao extends BaseDao{
    //接口里必须实现的方法,省略了public abstract
    /**
     * 根据用户ID查询用户
     */
    Users selectUsersById(int userid);
    /**
     * 修改用户信息
     */
    int updateUsersById(Users users);
}
因为baseDacImpl 的执行方法被继承了,可以用this . 即可
return this.executeUpdate(sql,param);
userdao实现类
package com.itbaizhan.dao.impl;
import com.itbaizhan.JdbcDruidUtill;
import com.itbaizhan.dao.UsersDao;
import com.itbaizhan.exception.ApplicationException;
import com.itbaizhan.pojo.Users;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
/**
 * 接口实现类
 */
public class UsersDaoImpl extends BaseDaoImpl  implements UsersDao {
    /**
     * 根据用户ID查询用户
     * @param userid
     * @return
     */
    @Override
    public Users selectUsersById(int userid) {
        Connection connection= null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Users users=null;
        try{
            connection= JdbcDruidUtill.getConnection();
            ps=connection.prepareStatement("select * from users where userid = ?");
            ps.setInt(1,userid);
            rs= ps.executeQuery();
            while(rs.next()){
                //手动ORM映射
                users=new Users();
                users.setUserid(rs.getInt("userid"));
                users.setUsername(rs.getString("username"));
                users.setUserage(rs.getInt("userage"));
            }
        }catch(Exception e){
            e.printStackTrace();
            //抛出自定义异常信息
            throw new ApplicationException(e.getMessage());
        }finally{
            JdbcDruidUtill.closeResource(rs,ps,connection);
        }
        return users;
    }
    /**
     * 修改用户信息
     * @param users
     * @return
     */
    @Override
    public int updateUsersById(Users users) {
        //只要准备好sql和参数即可
        String sql= "update users set userage = ? where userid =? ";
        //数组初始化方法一
        Object[] param ={users.getUserage(),users.getUserid()};
        //方法二
//        Object[] param=new Object[]{users.getUserage(),users.getUserid()};
        return this.executeUpdate(sql,param);
    }
}
usersservice接口
package com.itbaizhan.service;
import com.itbaizhan.pojo.Users;
public interface UsersService {
    Users findUsersById(int userid);
    int modifyUsersById(Users users);
}
 usersService实现类
添加重载的方法
    @Override
    public int modifyUsersById(Users users) {
        UsersDao ud=new UsersDaoImpl();
        return ud.updateUsersById(users);
    }

test2
package com.itbaizhan.web;
import com.itbaizhan.pojo.Users;
import com.itbaizhan.service.UsersService;
import com.itbaizhan.service.impl.UsersServiceImpl;
public class Test2 {
    public static void main(String[] args) {
        UsersService us=new UsersServiceImpl();
        //用Users来传递参数
        Users users=new Users();
        users.setUserage(23);
        users.setUserid(3);
        int i=us.modifyUsersById(users);
        //返回受影响的值
        System.out.println(i);
    }
}
业务差别就只在sql和参数里了
  • 封装通用的查询语句
1.查询多了一个映射的问题!
2.有返回值,返回list容器
3.泛型不确定,要占位符
4.映射到哪个实体当中(users/boys等表),要把实体的类模版告诉我( 即class对象告诉我),我可以通过反射把实体对象创建出来,然后再将结果集映射到实体对象里面
泛型的指定有两种方法:
在接口上添加个泛型,未来你在使用这个接口是,你给定接口定义这个接口的时间,给定了类型,那List就啥类型
public interface BaseDao<T> {}
将这个方法变成泛型方法,未来给这个方法什么类型,就是什么类型,在方法的返回值前面再加个泛型符号
<T> List<T> select(String sql ,Object[] param,Class<T> clazz);
这样就将通用方法的API已经创建出来了
package com.itbaizhan.dao;
import java.util.List;
/**
 * 通用接口
 */
public interface BaseDao {
    /**
     * 通用的DML操作方法
     */
    //返回DML操作中受影响的条数
    int  executeUpdate(String sql,Object [] param);
    /**
     * 通用查询方法
     */
   <T> List<T> select(String sql , Object[] param, Class<T> clazz);
}
在BaseDao的实现类里实现抽象方法:
1.得到参数个数绑定参数的过程查询里也要有,因为查询语句里面未来有多个参数的话,也需要向语句的问号当中绑定参数。
但不同的是下面要 写查询的sql执行语句,还要在外边再创建一个List的对象未来要装结果集
2.接下来查询结果集,就要在while 里面做ORM的映射了
3.查询出来的结果集的表也不知道有几列,要看查询语句投影几个列。要先知道投影了几个列,再根据列取里面的内容
1.通过反射先去实例化这个实体类对象:
clazz.newInstance();
2.返回泛型对象  :
 T bean=clazz.newInstance();
如果Class没给泛型的话,这个bean 就不能给泛型,而是给默认的Object类型了
        第一种方式:
通过反射,先去拿这个clazz这个实体类对象去反射它的属性
get declared field 拿到field返回一个field的数组,然后循坏这个数组,再通过这个数组的名字从结果集里get column  取结果集的列的值
注意:还有个硬性要求:实体类的属性名必须要和表的列名相同,不然没法进行通用操作,因为未来要通过这个属性名返回这个列的值
        第二种方法:
        通过第三方工具:
阿帕奇Coleman 项目下的一个叫BeanUtill的工具
通过它来完成结果集和实体对象的的属性的映射处理
用rm.getColumnName()获得列的名字,但是你查询出来的表的名字不知道,没办法在括号里输入列的名字,就输入列的位置,从1开始获取列的值
String columnName =rm.getColumnName(i+1);
Object value=rs.getObject(columnName);
通过BeanUtil工具类将值映射到对象中
要传三个参数:
        bean是往哪个对象里去做值的映射
        name是你当前要往这个对象的哪个属性里映射,属性名和表的列名一样的
        value是向这个属性中加入什么值
//最后将bean对象放入list 里
list.add(bean);
BaseDao实现类
 /**
     * 通用查询方法
     * @param sql
     * @param param
     * @param clazz
     * @return
     * @param <T>
     */
    @Override
    public <T> List<T> select(String sql, Object[] param, Class<T> clazz) {
        Connection connection =null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        List<T> list=new ArrayList<>();
        try{
            connection=JdbcDruidUtill.getConnection();
            ps=connection.prepareStatement(sql);
            //绑定参数
            //得到参数个数
            ParameterMetaData pd=ps.getParameterMetaData();
            for(int i=0;i<pd.getParameterCount();i++){
                ps.setObject(i+1,param[i]);
            }
            //执行语句
            rs=ps.executeQuery();
            //查询结果集
            //先获取结果集信息
            //rs.getMetaData();该方法返回一个ResultSetMetaData类型对象
            ResultSetMetaData rm =rs.getMetaData();
            while (rs.next()){
                //ORM 映射
                //通过反射先去实例化这个实体类对象
                T bean=clazz.newInstance();
               //实体类的属性名必须要和表的列名相同,不然没法进行通用操作
                for(int i=0 ;i< rm.getColumnCount();i++){
                    //先得到列名
                    String columnName =rm.getColumnName(i+1);
                    //获取列的值
                    Object value=rs.getObject(columnName);
                    //通过BeanUtil工具类将值映射到对象中
                    BeanUtils.setProperty(bean,columnName,value);
                }
                list.add(bean);
            }
        }catch(Exception e ){
            e.printStackTrace();
            throw new ApplicationException(e.getMessage());
        }finally{
            JdbcDruidUtill.closeResource(rs,ps,connection);
        }
        return list;
    }
通过继承usersDao已经具有了查询功能。然后在接口里再创建一个方法。因为是在UserDao里做的测试,那返回的一定是User类型。
UserDao接口
   /**
     * 根据用户姓名模糊查询
     */
    List<Users> selectUsersByLikeName(String username);
UserDao的实现类
Object[] param=new Object[]{"%"+username+"%"}; 
注意:不用写单引号,因为未来还是要依靠我们写的通用用方法实现参数绑定的
调用继承来的方法
最后一个参数是要放入的对象的模版对象
    @Override
    public List<Users> selectUsersByLikeName(String username) {
        String sql= " select * from users where username like ? ";
        Object[] param=new Object[]{"%"+username+"%"};
        return this.select(sql,param,Users.class);
    }

Userservice接口
List<Users> findUsersByLikeName(String username);
UserService实现类
还是先实例化UserDao对象
 @Override
    public List<Users> findUsersByLikeName(字符串用户名) {
        UsersDao ud=new UsersDaoImpl();
        返回 ud.selectUsersByLikeName(username);
测试类test3
实例化是逐级调用的
package com.itbaizhan.web;
import com.itbaizhan.pojo.Users;
import com.itbaizhan.service.UsersService;
import com.itbaizhan.service.impl.UsersServiceImpl;
import java.util.List;
public class Test3 {
    public static void main(String[] args) {
        UsersService us=new UsersServiceImpl();
        List<Users> list =us.findUsersByLikeName("l");
        //再将list遍历
        for(Users user :list  ){
            System.out.println(user);
        }
    }
}

     对象关联关系

关联关系简介:

关联关系(Association),是一种拥有的关系,它使一个对象知道另一个对象的属性和方法。关联可以是双向的,也可以是单向的。在Java语言中,关联关系一般使用成员变量来实现users关联了orders
问题:
对象的关联关系解决了什么问题?
解答:
在多表查询时,使用对象关联关系能够更合理的存放查询到的结果集数据。

关联关系的方向性:

1.单向
只在一侧关联了对方。
2.双向
两侧相互关联了对方
  • 创建对象

创建表:
一对多,用外键的方式,多方必用外键
可以通过图形化创建,再比对的方法
创建表
CREATE TABLE `orders` (
  `orderid` int(11) NOT NULL AUTO_INCREMENT,
  `orderprice` float(11,2) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`orderid`),
  KEY `orders_fk` (`user_id`),
  CONSTRAINT `orders_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
建立三者双向关系
Users

    //创建与orders 的关联关系
    //如果是一对一的关系,则可以将方法设置为Orders
    //但这是一对多的关系,所以用List类型
    private List<Orders> orders =new ArrayList<>();
orders
package com.itbaizhan.pojo;
import sun.swing.BakedArrayList;
import java.util.ArrayList;
import java.util.List;
public class Orders {
    private  int orderid;
    private double orderprice;
    //不要创建users_id 因为这是用来查询Users对象
    //关联Users
    //从订单看用户的话,一个订单只对应一个用户
    //集合要new 出来,关联的一个对象就不要new出来了
    private Users users;
    //关联Items(集合)
    private List<Items> items=new ArrayList();
    public int getOrderid() {
        return orderid;
    }
    public void setOrderid(int orderid) {
        this.orderid = orderid;
    }
    public double getOrderprice() {
        return orderprice;
    }
    public void setOrderprice(double orderprice) {
        this.orderprice = orderprice;
    }
    public Users getUsers() {
        return users;
    }
    public void setUsers(Users users) {
        this.users = users;
    }
    public List<Items> getItems() {
        return items;
    }
    public void setItems(List<Items> items) {
        this.items = items;
    }
}
items
package com.itbaizhan.pojo;
import java.util.ArrayList;
import java.util.List;
public class Items {
    private int itemid;
    private String itemname;
    private double itemprice;
    private int itemnum;
    //关联Orders
    private List<Orders> orders=new ArrayList<>();
    public int getItemid() {
        return itemid;
    }
    public void setItemid(int itemid) {
        this.itemid = itemid;
    }
    public String getItemname() {
        return itemname;
    }
    public void setItemname(String itemname) {
        this.itemname = itemname;
    }
    public double getItemprice() {
        return itemprice;
    }
    public void setItemprice(double itemprice) {
        this.itemprice = itemprice;
    }
    public int getItemnum() {
        return itemnum;
    }
    public void setItemnum(int itemnum) {
        this.itemnum = itemnum;
    }
    public List<Orders> getOrders() {
        return orders;
    }
    public void setOrders(List<Orders> orders) {
        this.orders = orders;
    }
}
  • 使用关联对象存放查询数据

输入点数据
select * from users u ,orders o ,order_items oi ,items i where u.userid=o.user_id and o.orderid=oi.order_id and oi.item_id=i.itemid 
and u.userid=1
根据ID查得返回的一定是Users,Users关联Orders,Items
UserDao:
    /**
     * 查询用户ID为1的用户信息积极他的订单信息
     * 以及订单中的所包含的商品信息
     */
    Users selectUsers (int userid);
UsersDaoImpl:
 /**
     * 查询用户ID为1的用户信息积极他的订单信息
     * 以及订单中的所包含的商品信息
     */
    @Override
    public Users selectUsers(int userid) {
        Connection connection=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Users users=new Users();
        try{
            connection= JdbcDruidUtill.getConnection();
            ps=connection.prepareStatement("select * from users u ,orders o ,order_items oi ,items i where u.userid=o.user_id and o.orderid=oi.order_id and oi.item_id=i.itemid and u.userid=?");
            ps.setInt(1,userid);
            rs= ps.executeQuery();
            while (rs.next()){
                //users对象的ORM映射
                users.setUserid(rs.getInt("userid"));
                users.setUsername(rs.getString("username"));
                users.setUserage(rs.getInt("userage"));
                //Orders对象的ORM映射
                Orders orders=new Orders();
                orders.setOrderid(rs.getInt("orderid"));
                orders.setOrderprice(rs.getDouble("orderprice"));
               //orders是容器类型
                users.getOrders().add(orders);
                //Items 对象的映射
                Items items=new Items();
                items.setItemid(rs.getInt("itemid"));
                items.setItemname(rs.getString("itemname"));
                items.setItemnum(rs.getInt("itemnum"));
                items.setItemprice(rs.getDouble("itemprice"));
                orders.getItems().add(items);
            }
            }catch(Exception e){
            e.printStackTrace();
            //抛出自定义异常信息
            throw new ApplicationException(e.getMessage());
        }finally{
            JdbcDruidUtill.closeResource(rs,ps,connection);
        }
        return users;
    }
UsersService:
 Users findUsers(int userid);
UserServixeImpl:
    @Override
    public Users findUsers(int userid) {
        UsersDao ud=new UsersDaoImpl();
        return ud.selectUsers(userid);
    }
test4:
package com.itbaizhan.web;
import com.itbaizhan.pojo.Items;
import com.itbaizhan.pojo.Orders;
import com.itbaizhan.pojo.Users;
import com.itbaizhan.service.UsersService;
import com.itbaizhan.service.impl.UsersServiceImpl;
import java.util.List;
public class Test4 {
    public static void main(String[] args) {
        UsersService us = new UsersServiceImpl();
        Users users = us.findUsers(1);
        System.out.println("users:" + users.getUserid() + " " + users.getUsername() + " " + users.getUserage());
        List<Orders> list = users.getOrders();
        for (Orders orders : list) {
            System.out.println("orders:" + orders.getOrderid() + " " + orders.getOrderprice());
            List<Items> items = orders.getItems();
            for (Items item : items) {
                System.out.println("Items:" + item.getItemid() + " " + item.getItemname() + " " + item.getItemprice() + " " + item.getItemnum());
            }
        }
    }
}

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值