JDBC核心技术10.23

it2025-07-21  11

第三章 使用PreparedStatement实现CRUD操作

3.1 操作和访问数据库

数据库连接被用于数据库服务器发送命令和SQL语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。在java.sql包中有3个接口分别定义了对数据库的调用的不同方式: - Statement:用于执行静态SQL语句并返回它所生成结果的对象。 - PreparedStatement:SQL语句被预编译并存储在此对象中,可以使用此对象多次高效的执行该语句。 - CallableStatement:用于执行SQL存储过程。

3.2 使用Statement操作数据表的弊端

通过调用Connection对象的createStatement()方法创建该对象。该对象用于执行静态的SQL语句,并返回执行结果。Statement接口中定义了下列方法用于执行SQL语句: int excuteUpdate(String sql):执行更新操作Insertupdatedelete ResultSet executeQuery(String sql):执行查询操作Select 但是使用Statement操作数据表存在弊端: 问题1:存在拼串操作,繁琐问题2:存在SQL注入问题 SQL注入是利用某些系统没有队用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令。对于Java而言,要防范SQL注入,只要用PreparedStatement(从Statement扩展而来)取代Statement就可以了。 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入用户名:"); String user = scanner.next(); System.out.println("请输入密码:"); String password = scanner.next(); String sql = "select user,password from user_table where user = '"+user+"'and password = '"+password+"'"; User returnUser = get(sql,User.class); if(returnUser != null){ System.out.println("登录成功"); }else{ System.out.println("用户名不存在或密码错误"); } }

3.3 PreparedStatement的使用

3.3.1PreparedStatement介绍

3.3.2 使用Statement操作数据表的弊端

通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。

Statement 接口中定义了下列方法用于执行 SQL 语句: int excuteUpdate(String sql):执行更新操作INSERT、UPDATE、DELETE ResultSet executeQuery(String sql):执行查询操作SELECT

使用Statement操作数据表存在弊端:

问题一:存在拼串操作,繁琐 问题二:存在SQL注入问题 SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的做法。

要防范 SQL 注入,只要用 PreparedStatemen取代 Statement 就可以了。

// 使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入用户名:"); String user = scanner.next(); System.out.println("请输入密码:"); String password = scanner.next(); String sql = "select user,password from user_table where user = '"+user+"'and password = '"+password+"'"; User returnUser = get(sql,User.class); if(returnUser != null){ System.out.println("登录成功"); }else{ System.out.println("用户名不存在或密码错误"); } } // 使用Statement实现对数据表的查询操作 public static <T> T get(String sql, Class<T> clazz) { T t = null; Connection conn = null; Statement st = null; ResultSet rs = null; try { // 1.加载配置文件 InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("com/atguigu/statement/crud/jdbc.properties"); Properties pros = new Properties(); pros.load(is); // 2.读取配置信息 String user = pros.getProperty("user"); String password = pros.getProperty("password"); String url = pros.getProperty("url"); String driverClass = pros.getProperty("driverClass"); // 3.加载驱动 Class.forName(driverClass); // 4.获取连接 conn = DriverManager.getConnection(url, user, password); st = conn.createStatement(); rs = st.executeQuery(sql); // 获取结果集的元数据 ResultSetMetaData rsmd = rs.getMetaData(); // 获取结果集的列数 int columnCount = rsmd.getColumnCount(); if (rs.next()) { t = clazz.newInstance(); for (int i = 0; i < columnCount; i++) { // //1. 获取列的名称 // String columnName = rsmd.getColumnName(i+1); // 1. 获取列的别名 String columnName = rsmd.getColumnLabel(i + 1); // 2. 根据列名获取对应数据表中的数据 Object columnVal = rs.getObject(columnName); // 3. 将数据表中得到的数据,封装进对象 Field field = clazz.getDeclaredField(columnName); field.setAccessible(true); field.set(t, columnVal); } return t; } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (st != null) { try { st.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } return null; }

3.3.1 Java与SQL对应数据类型转换表

3.3.4 使用PreparedStatement实现增、删、改操作

//向customers表添加一条记录 public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; try { //向customs表中添加一条记录 //1.读取配置文件中的4个基本信息 InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("com/atguigu/statement/crud/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.获取连接 conn = DriverManager.getConnection(url, user, password); System.out.println(conn); //4.预编译sql语句,返回PreparedStatement的实例 String sql = "insert into customers(name,email,birth) values(?,?,?)";//?:占位符 ps = conn.prepareStatement(sql); //5.填充占位符 ps.setString(1,"奥斯卡"); ps.setString(2,"2836440891@qq.com"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); java.util.Date date = sdf.parse("1999-12-21"); ps.setDate(3, new Date(date.getTime())); //6.执行操作 ps.execute(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } finally { //7.资源管理 try { if(ps!=null) ps.close(); } catch (SQLException e) { e.printStackTrace(); } try { if(conn!=null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } //修改customers表的一条记录 @Test public void testUpdate() { Connection conn = null; PreparedStatement ps = null;//预编译Sql语句 try { //1.获取数据库的连接 conn = JDBCUtils.getConnection(); //2.预编译SQL语句返回PreparedStatement实例 String sql = "update customers set name = ? where id = ?"; ps = conn.prepareStatement(sql); //3.填充占位符 ps.setObject(1,"莫扎特"); ps.setObject(2,18); //4.执行 ps.execute(); } catch (Exception e) { e.printStackTrace(); }finally { //5.资源的关闭 JDBCUtils.closeResource(conn,ps); } } //通用的增删改操作 public void update(String sql ,Object ...args){ Connection conn = null; PreparedStatement ps = null; try { //sql中占位符的个数与可变形参的长度一致 //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 testCommonUpdate(){ // String sql = "delete from customers where id =?"; // update(sql,3); String sql = "update `order` set order_name = ? where order_id = ?"; update(sql,"DD","2"); }

3.3.5 使用PreparedStatement实现查询操作

@Test public void testQuery1() throws Exception{ Connection conn = JDBCUtils.getConnection(); String sql = "select id,name,email,birth from customers where id =?"; PreparedStatement ps = conn.prepareStatement(sql); //执行,并返回结果集 ResultSet resultSet = ps.executeQuery(); //处理结果集 if(resultSet.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); } JDBCUtils.closeResource(conn ,ps,resultSet); } }

3.4ResultSet与ResultSetMetaData

3.4.1 ResultSet

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

3.4.2 ResultSetMetaData

可用于获取关于 ResultSet 对象中列的类型和属性信息的对象通过调用ResultSet对象的getMetaData()方法获得ResultSetMetaData对象 - getColumnName(int column):获取指定列的名称 - getColumnLabel(int column):获取指定列的别名 - getColumnCount():返回当前 ResultSet 对象中的列数。

3.5 资源的释放

- 释放ResultSet, Statement,Connection。 - 数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统问题。Connection的使用原则是尽量晚创建,尽量早的释放。 - 可以在finally中关闭,保证及时其他代码出现异常,资源也一定能被关闭。

3.6 JDBC API小结

两种思想

面向接口编程的思想 ORM思想(object relational mapping) 1. 一个数据表对应一个java类 2. 表中的一条记录对应java类的一个对象 3. 表中的一个字段对应java类的一个属性

两种技术

JDBC结果集的元数据:ResultSetMetaData -获取列数:getColumnCount() -获取列的别名:getColumnLabel() 通过反射,创建指定类的对象,获取指定的属性并赋值
最新回复(0)