使用PreparedStatement实现CRUD操作

目录

一、操作和访问数据库

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

二、使用Statement操作数据表的弊端

三、使用PreparedStatement替换Statement,实现对数据表的增删改查操作

1.添加数据 

 ⚪封装数据库连接和关闭操作

2.修改数据

3.通用的增删改操作

删除测试

4.查询数据 

例1:针对于Customers表的查询操作

例2:针对于customers表的通用的查询操作 

⚪图解查询操作的流程 ​

例3:针对于不同表的查询操作

①ORM编程思想

②java与sql对应数据类型转换表 ​

③ResultSet与ResultSetMetaData

Ⅰ.ResultSet 

​Ⅱ.ResultSetMetaData 


一、操作和访问数据库

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

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

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

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

二、使用Statement操作数据表的弊端

  • 问题一:存在拼串操作,繁琐
  • 问题二:存在SQL注入问题 

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的做法。

对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。 

三、使用PreparedStatement替换Statement,实现对数据表的增删改查操作

1.添加数据 

import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

public class PreparedStatementUpdateTest {
    //向departments中添加一条记录
    @Test
    public void test1(){
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            //1.读取配置文件中的4个基本信息
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");

            Properties pros = new Properties();
            pros.load(is);

            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            String url = pros.getProperty("url");
            String driverClass = pros.getProperty("driverClass");
            //2.加载驱动
            Class.forName(driverClass);

            //3.获取连接
            connection = DriverManager.getConnection(url, user, password);
            //4.预编译sql语句,返回PreparedStatement实例
            String sql = "insert into departments(department_id,department_name,manager_id,location_id)values(?,?,?,?)";//?:占位符
            ps = connection.prepareStatement(sql);

            //5.填充占位符
            ps.setString(1,"280");
            ps.setString(2,"shopping");
            ps.setString(3,"260");
            ps.setString(4,"1800");

            //如果需要插入时间
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        java.util.Date date = sdf.parse("1000-01-01");
//        ps.setDate(4, (java.sql.Date) new Date(date.getTime()));

            //6.执行操作
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //7.资源的关闭
            try {
                if(ps != null)
                   ps.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                if(connection != null)
                    connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

上述操作会报错,因为departments没有主键约束或唯一性约束 

 ⚪封装数据库连接和关闭操作

在新建的包中

import connection.ConnectionTest;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

//操作数据库的工具类
public class JDBCUtils {
    //获取数据库的连接
    public static Connection getConnection() throws Exception {
        //1.读取配置文件中的4个基本信息
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        //获取系统类加载器

        Properties pros = new Properties();
        pros.load(is);

        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");
        //2.加载驱动
        Class.forName(driverClass);

        //3.获取连接
        Connection connection = DriverManager.getConnection(url, user, password);

        return connection;
    }

    //关闭连接
    public void closeResource(Connection conn, Statement ps){
        try {
            if(ps != null)
                ps.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if(conn != null)
                conn.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

2.修改数据

//修改countries表中的一条数据
@Test
public void test2(){
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        //1.获取数据库的连接
        conn = JDBCUtils.getConnection();
        //2.预编译sql语句,返回PreparedStatement实例
        String sql = "update countries set country_name = ? where country_id = ?";
        ps = conn.prepareStatement(sql);
        //3.填充占位符
        ps.setObject(1,"CHINA");
        ps.setObject(2,"CH");
        //4.执行
        ps.execute();
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        //5.资源的关闭
        JDBCUtils.closeResource(conn,ps);
    }
}

3.通用的增删改操作

public void update(String sql,Object ...args){//sql中占位符的个数与可变形参的长度相同
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        //1.获取数据库的连接
        conn = JDBCUtils.getConnection();
        //2.预编译sql语句,返回PreparedStatement实例
        ps = conn.prepareStatement(sql);
        //3.填充占位符
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i + 1,args[i]); //小心参数声明错误
        }
        //4.执行
        ps.execute();
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        //5.关闭资源
        JDBCUtils.closeResource(conn,ps);
    }
}

删除测试

@Test
public void test3(){
    //删除操作
    String sql = "delete from countries where country_id = ?";
    update(sql,"JP");
}

4.查询数据 

例1:针对于Customers表的查询操作

@Test
public void test1(){
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet resultSet = null;
    try {
        conn = JDBCUtils.getConnection();
        String sql = "select id,name,email,birth from customers where id = ?";
        ps = conn.prepareStatement(sql);
        ps.setObject(1,1);
        //执行,并返回结果集
        resultSet = ps.executeQuery();
        //处理结果集
        if (resultSet.next()){//next():判断结果集的下一条是否有数据,如果有数据,返回true并指针下移;如果返回false,指针不会下移
            //获取当前这条数据的各个字段值
            int id = resultSet.getInt(1);
            String name = resultSet.getString(2);
            String email = resultSet.getString(3);
            Date birth = resultSet.getDate(4);
            //方式一:
//            System.out.println("id = " + id + ",name = " + name + ",email = " + email +",birth = " + birth);
            //方式二:
//            Object[] data = new Object[]{id,name,email,birth};
            //方式三:将数据封装为一个对象(推荐方式)
            Customer customer = new Customer(id,name,email,birth);
            System.out.println(customer);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        //关闭资源
        JDBCUtils.closeResource(conn,ps,resultSet);
    }
}
package bean;

import java.util.Date;

//ORM编程思想(object relational mapping —— 对象关系映射)
public class Customer {
    private int id;
    private String name;
    private String email;
    private Date birth;

    public Customer() {
    }

    public Customer(int id, String name, String email, Date birth) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.birth = birth;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", birth=" + birth +
                '}';
    }
}
//关闭资源的操作
public static void closeResource(Connection conn, Statement ps, ResultSet rs){
    try {
        if(ps != null)
            ps.close();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    try {
        if(conn != null)
            conn.close();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    try {
        if(rs != null)
            rs.close();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
}

例2:针对于customers表的通用的查询操作 

获取结果集的元数据

ResultSetMetaData rsmd = rs.getMetaData();

通过获取结果集中的元数据获取结果集的列数

public Customer queryForCustomers(String sql,Object ...args){
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        conn = JDBCUtils.getConnection();
        ps = conn.prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i+1,args[i]);
        }
        rs = ps.executeQuery();
        //获取结果集的元数据
        ResultSetMetaData rsmd = rs.getMetaData();
        //通过获取结果集中的元数据获取结果集的列数        
        int columnCount = rsmd.getColumnCount();
        if (rs.next()){
            Customer cust = new Customer();
            //处理一行数据中的每一个列
            for (int i = 0; i < columnCount; i++) {
                //获取列值
                Object columnValue = rs.getObject(i + 1);//获取到字段的值
                //获取每个列的列名
                String columnName = rsmd.getColumnName(i + 1);
                //给cust对象指定的columnName属性赋值为columnValue:通过反射
                Field field = Customer.class.getDeclaredField(columnName);
                field.setAccessible(true);
                field.set(cust,columnValue);
            }
            return cust;
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtils.closeResource(conn,ps,rs);            
    }
    return null;
}

测试

@Test
public void test4(){
    String sql = "select id,name,birth,email from customers where id = ?";
    Customer customer = queryForCustomers(sql, 13);
    System.out.println(customer);
}

⚪图解查询操作的流程 

例3:针对于不同表的查询操作

⚪针对于不同的表的通用的查询操作,此时返回一个表中的一条记录

import bean.Customer;
import com.mysql.cj.x.protobuf.MysqlxCrud;
import org.junit.Test;
import util.JDBCUtils;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

public class PreparedStatementQueryTest {
    @Test
    public void test1(){
        String sql = "select id,name,email from customers where id = ?";
        Customer customer = getInstance(Customer.class, sql, 12);
        System.out.println(customer);

        String sql1 = "select order_id orderId,order_name orderName from `order` where order_id = ?";
        Order order = getInstance(Order.class, sql1, 1);
        System.out.println(order);
    }


    public <T> T getInstance(Class<T> clazz,String sql,Object ...args){ //使用泛型方法
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtils.getConnection();
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过获取结果集中的元数据获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            if (rs.next()){
                T t = clazz.newInstance();
                //处理一行数据中的每一个列
                for (int i = 0; i < columnCount; i++) {
                    //获取列值
                    Object columnValue = rs.getObject(i + 1);//获取到字段的值
                    //获取每个列的列名
                    String columnName = rsmd.getColumnName(i + 1);
                    //给t对象指定的columnName属性赋值为columnValue:通过反射
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnValue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,ps,rs);
        }
        return null;
    }
}

⚪ 针对于不同的表的通用的查询操作,此时返回一个表中的多条记录

    @Test
    public void test2(){
        String sql  = "select id,name,email from customers where id < ?";
        List<Customer> list = getForList(Customer.class, sql, 12);
        list.forEach(System.out::println);
    }

    public <T> List<T> getForList(Class<T> clazz,String sql,Object ...args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtils.getConnection();
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }
            rs = ps.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过获取结果集中的元数据获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            //创建集合对象:给t对象指定的属性赋值
            ArrayList<T> list = new ArrayList<>();
            while (rs.next()){
                T t = clazz.newInstance();
                //处理一行数据中的每一个列
                for (int i = 0; i < columnCount; i++) {
                    //获取列值
                    Object columnValue = rs.getObject(i + 1);//获取到字段的值
                    //获取每个列的列名
                    String columnName = rsmd.getColumnName(i + 1);
                    //给t对象指定的columnName属性赋值为columnValue:通过反射
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnValue);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(conn,ps,rs);
        }
        return null;
    }

①ORM编程思想

object relational mapping:对象关系映射

一个数据表对应一个Java类

表中的一条记录对应Java类的一个对象

表中的一个字段对应Java类的一个属性

②java与sql对应数据类型转换表 

③ResultSet与ResultSetMetaData

Ⅰ.ResultSet 

  • 查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象
  • ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现
  • ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。
  • ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。 相当于Iterator对象的 hasNext() 和 next() 方法的结合体。
  • 当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。

注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。

Ⅱ.ResultSetMetaData 

可用于获取关于 ResultSet 对象中列的类型和属性信息的对象

ResultSetMetaData meta = rs.getMetaData();

  • getColumnName(int column):获取指定列的名称
  • getColumnLabel(int column):获取指定列的别名 
  • getColumnCount():返回当前 ResultSet 对象中的列数。
  • getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
  • getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
  • isNullable(int column):指示指定列中的值是否可以为 null。
  • isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

elk-zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值