PreparedStatement实现对表数据的增删改查操作

编程入门 行业动态 更新时间:2024-10-22 17:30:21

PreparedStatement实现对表数据的增删改查<a href=https://www.elefans.com/category/jswz/34/1770947.html style=操作"/>

PreparedStatement实现对表数据的增删改查操作

对PreparedStatement的使用的插入案例进行封装如下

JDBCUtils.java

package com.atmf;import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Properties;import org.junit.Test;public class JDBCUtils {/*** @Describe 获取数据库的连接* @auther mofei* @date 2020年11月3日下午6:25:54*/public static Connection getConnection() throws Exception{//1,加载配置文件InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");Properties pr = new Properties();pr.load(is);//2,读取配置信息String user = pr.getProperty("user");String password = pr.getProperty("password");String url = pr.getProperty("url");String driverClass = pr.getProperty("driverClass");//3.加载驱动Class.forName(driverClass);//4,获取连接Connection con = DriverManager.getConnection(url, user,password);return con;}//增删改资源的关闭public static void closeReource(Connection con, PreparedStatement ps){try {if(ps != null)ps.close();} catch (Exception e) {e.printStackTrace();}try {if(con != null)con.close();} catch (Exception e) {e.printStackTrace();}}//查询资源的关闭public static void closeResource(java.sql.Connection con, PreparedStatement ps, ResultSet rs){try {if(con != null)con.close();} catch (SQLException e) {e.printStackTrace();}try {if(ps != null)ps.close();} catch (SQLException e) {e.printStackTrace();}try {if(rs != null)rs.close();} catch (SQLException e) {e.printStackTrace();}}	
}

对表进行增删改操作


修改

package com.atmf;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;import org.junit.Test;public class PreparedStatementUpdateTest {@Testpublic void testUpdate() {		Connection con = null;PreparedStatement ps = null;try {//1,获取数据库的连接con = JDBCUtils.getConnection();//2,预编译sql语句,返回PreparedStatement的实例String sql = "update customers set name = ? where id = ?";ps = con.prepareStatement(sql);//3,填充占位符ps.setObject(1, "提莫");ps.setObject(2, 1);//4,执行ps.execute();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {//5,资源的关闭JDBCUtils.closeReource(con, ps);}}
}

结果:


插入

package com.atmf;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;import org.junit.Test;public class PreparedStatementUpdateTest {@Testpublic void testUpdate() {		Connection con = null;PreparedStatement ps = null;try {//1,获取数据库的连接con = JDBCUtils.getConnection();//2,预编译sql语句,返回PreparedStatement的实例String sql = "insert into customers(name) value(?)";ps = con.prepareStatement(sql);//3,填充占位符ps.setObject(1, "王者农药");SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");Date date = sdf.parse("1995-11-03");ps.setDate(2, new java.sql.Date(date.getTime()));//4,执行ps.execute();} catch (SQLException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {//5,资源的关闭JDBCUtils.closeReource(con, ps);}}
}


删除

package com.atmf;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;import org.junit.Test;public class PreparedStatementUpdateTest {@Testpublic void testUpdate() {		Connection con = null;PreparedStatement ps = null;try {//1,获取数据库的连接con = JDBCUtils.getConnection();//2,预编译sql语句,返回PreparedStatement的实例String sql = "delete from customers where id = ?";ps = con.prepareStatement(sql);//3,填充占位符ps.setObject(1, 3);//4,执行ps.execute();} catch (SQLException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {//5,资源的关闭JDBCUtils.closeReource(con, ps);}}
}


以上,对表的增删改操作之间的不同就是SQL语句的不同,将其进行封装从而实现对同一数据库中表的增删改操作的通用,通过调用update()方法就能完成,代码如下所示。


通用的增删改操作

	public void update(String sql, Object ...args) {Connection con =null;PreparedStatement ps = null;try {//1,获取数据库的连接con = JDBCUtils.getConnection();//2,预编译sql语句,返回PreparedStatement的实例ps = con.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.closeReource(con, ps);}		}

对表进行查询操作

                     ORM编程思想
  对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
  对象数据库是一种以对象形式表示信息的数据库。对象数据库的数据库管理系统被称为ODBMS或OODBMS。
  两个主要原因让用户使用对象数据库技术。首先,关系数据库在管理复杂数据时显得笨重。其次,被应用软件操作的数据一般是用面向对象的编程语言如C++,Java,Delphi和C#写成,而那些用来转化数据表示和关系数据库元组的代码很冗繁,执行时也有不少耗时。这种应用程序和数据库表示信息的模式之间的不匹配有时也被称为impedance mismatch。
  简单来讲:一个数据表对应一个java类,表中的一条记录对应java类的一个对象,表中的一个字段对应java类的一个属性

Java与SQL对应数据类型转换表
Java类型SQL类型
booleanBIT
byteTINYINT
shortSMALLINT
intINTEGER
longBIGINT
StringCHAR,VARCHAR,LONGVARCHAR
byte arrayBINARY , VAR BINARY
java.sql.DateDATE
java.sql.TimeTIME
java.sql.TimestampTIMESTAMP

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

  • ResultSetMetaData rsmd = rs.getMetaData();

    • getColumnName(int column):获取指定列的名称

    • getColumnLabel(int column):获取指定列的别名

    • getColumnCount():返回当前 ResultSet 对象中的列数。

    • getColumnTypeName(int column):检索指定列的数据库特定的类型名称。

    • getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。

    • isNullable(int column):指示指定列中的值是否可以为 null。

    • isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。


第一个查询操作

第一步:建立数据库及表

CREATE DATABASE test;
USE test;
CREATE TABLE customers(`id` INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,`name` VARCHAR(15) DEFAULT NULL,`email` VARCHAR(20) DEFAULT NULL,`birth` DATE DEFAULT NULL,`photo` MEDIUMBLOB DEFAULT NULL
);
INSERT INTO customers(`name`,`email`,`birth`) 
VALUES('君莫笑','yege@qzgs','2035-05-29'),
('苏沐橙','mucheng@)qzgs','2042-02-18'),
('黄少天','hualao@qzgs','2038-06-12');

第二步:创建一个数据库对象映射的java类

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;}@Overridepublic String toString() {return "Customer{" +"id=" + id +", name='" + name + '\'' +", email='" + email + '\'' +", birth=" + birth +'}';}
}

第三步:创建配置文件

user=root
password=123456
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver

第四步:案例测试

    @Testpublic void queryTest() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {//建立连接conn = JDBCUtils.getConnection();//预编译sql语句String sql = "select id,name,email,birth from customers where id = ?";ps = conn.prepareStatement(sql);//填充占位符ps.setInt(1,1);//执行,并返回结果集rs = ps.executeQuery();//处理结果集if(rs.next()){//获取当前这条数据的各个字段值int id = rs.getInt(1);String name = rs.getString(2);String email = rs.getString(3);Date birth = rs.getDate(4);System.out.println(new Customer(id,name,email,birth));}} catch (Exception e) {e.printStackTrace();} finally {//关闭资源(关闭conn连接,ps,rs)
//        ps.close();//立即释放这个语句对象的数据库和JDBC资源,而不是等待它自动关闭时发生。通常好的做法是在使用完资源后立即释放它们,以避免占用数据库资源。
//        conn.close();//立即释放这个连接对象的数据库和JDBC资源,而不是等待它们被自动释放
//        rs.close();//立即释放这个ResultSet对象的数据库和JDBC资源,而不是在自动关闭时等待该操作发生。//将上面的是三个关闭资源写入JDBCUtils.java文件(本篇开头那个文件)中直接调用JDBCUtils.closeResource(conn,ps,rs);}}

第五步:控制台打印结果显示

Customer{id=1, name='君莫笑', email='yege@qzgs', birth=2035-05-29}

-------------------------------------------------------------------------------------------------------------------------

涉及到 ResultSet()—>结果集ResultSetMetaData()—>结果集元数据反射

针对于各自的表的通用查询

通用的查询操作1

常用的方法:

ResultSet
  • 查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象

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

  • ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。

  • ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的 hasNext() 和 next() 方法的结合体。

  • 当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。

    • 例如: getInt(1), getString(“name”)
    • 注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。

Object getObject(int columnIndex) throws SQLException;


用到的方法:

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

  • ResultSetMetaData rsmd = rs.getMetaData();

    • getColumnName(int column):获取指定列的名称

    • getColumnLabel(int column):获取指定列的别名

    • getColumnCount():返回当前 ResultSet 对象中的列数。

    • getColumnTypeName(int column):检索指定列的数据库特定的类型名称。

    • getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。

    • isNullable(int column):指示指定列中的值是否可以为 null。

    • isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。


    //通用查询操作public Customer queryForCustomers(String sql,Object ...args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {//第一步:获取连接conn = JDBCUtils.getConnection();//第二步:预编译sql语句 将查询语句手动输入,args表示可变的占位符参数ps = conn.prepareStatement(sql);//第三步:填充占位符for(int i = 0;i < args.length;i++){ps.setObject(i + 1,args[i]);//占位符参数索引是从1开始的}//第四步:执行,并返回结果集rs = ps.executeQuery();//第五步:处理结果集//如果有数据,就去取数据,但是取几次呢???这就需要结果集元数据(ResultSetMetaData getMetaData():检索此ResultSet对象的列的数量、类型和属性。)ResultSetMetaData rsmd = rs.getMetaData();//获取结果集的列数int columnCount = rsmd.getColumnCount();if(rs.next()){Customer customer = new Customer();//处理结果集一行数据中的每一个列for(int i = 0;i < columnCount;i++){//获得结果集上的列值Object columnValue = rs.getObject(i + 1);//获得值对应的列名字段String columnName = rsmd.getColumnName(i + 1);//通过反射给customer对象指定的columnClassName属性,赋值为columnValueField field = Customer.class.getDeclaredField(columnName);field.setAccessible(true);field.set(customer,columnValue);//第一个参数:要传入设置的对象,第二个参数:要传入实参}return customer;}} catch (Exception e) {e.printStackTrace();} finally {//第六步:关闭资源JDBCUtils.closeResource(conn,ps,rs);}//如果没有结果,返回nullreturn null;}

测试:

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

结果打印:

Customer{id=2, name='苏沐橙', email='mucheng@)qzgs', birth=2042-02-18}

通用的查询操作2

说明通用查询操作2与通用查询操作1就只有2行代码不同
1,sql字符串的书写不同
2,将获取每个列的列名:getColumnName() ———替换为————>获取每个列的别名:getColumnLabel()
3,在数据库字段名与java中属性名一致情况下,可以使用getColumnName(),反之,则会报错:没有这个字段
4,如果sql中没有给字段中起别名,getColumnLabel()获取的就是别名,所以不管有没有写别名都可以使用用getColumnLabel(尽量使用getColumnLabel)

将数据库test中customers表的字段名更改一下,以致表字段名与数据库对象映射的java类中的属性名不一致,或者另外创建一个表acg,表结构如下:

CREATE TABLE acg(id INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,`acg_name` VARCHAR(15) DEFAULT NULL,`acg_email` VARCHAR(20) DEFAULT NULL,`acg_birth` DATE DEFAULT NULL,`acg_photo` MEDIUMBLOB DEFAULT NULL
);
INSERT INTO acg(`acg_name`,`acg_email`,`acg_birth`) 
VALUES('君莫笑','yege@qzgs','2035-05-29'),
('苏沐橙','mucheng@)qzgs','2042-02-18'),
('黄少天','hualao@qzgs','2038-06-12');

同时数据库对象映射的java类中的属性名也要更改,使用驼峰命名法:

public class Acg {private int acgId;private String acgName;private String acgEmail;private Date acgBirth;...

其余保持不变。进行测试:

    public Acg queryForCustomers2(String sql,Object ...args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {//获得连接conn = JDBCUtils.getConnection();//预编译sql语句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()){Acg acg = new Acg();for(int i = 0;i < columnCount;i++){Object columnValue = rs.getObject(i + 1);String columnLabel = rsmd.getColumnLabel(i + 1);//通过反射给customer对象指定的columnClassName属性,赋值为columnValueField field = Acg.class.getDeclaredField(columnLabel);field.setAccessible(true);field.set(acg,columnValue);}return acg;}} catch (Exception e) {e.printStackTrace();} finally {//关闭资源JDBCUtils.closeResource(conn,ps,rs);}return null;}

测试:

    @Testpublic void queryForCustomersTest2() {String sql = "select acg_id acgId,acg_name acgName,acg_email acgEmail,acg_birth acgBirth from acg where acg_id = ?";Acg acg = queryForCustomers2(sql, 3);System.out.println(acg);}

结果打印:

Acg{acgId=3, acgName='黄少天', acgEmail='hualao@qzgs', acgBirth=2038-06-12}

-------------------------------------------------------------------------------------------------------------------------

针对于通用的表的通用查询

通用的表的查询操作,用于返回数据表中的一条记录

使用泛型方法

public class PreparedStatementTest {public <T> T queryForTable(Class<T> clazz,String sql,Object ...args){Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {//获得连接conn = JDBCUtils.getConnection();//预编译sql语句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 columnLabel = rsmd.getColumnLabel(i + 1);//通过反射给customer对象指定的columnClassName属性,赋值为columnValueField field = clazz.getDeclaredField(columnLabel);field.setAccessible(true);field.set(t,columnValue);}return t;}} catch (Exception e) {e.printStackTrace();} finally {//关闭资源JDBCUtils.closeResource(conn,ps,rs);}return null;}@Testpublic void queryForTableTest(){String sql1 = "select id,name,birth,email from customers where id = ?";Customer customer = queryForTable(Customer.class,sql1, 1);System.out.println(customer);String sql2 = "select acg_id acgId,acg_name acgName,acg_email acgEmail,acg_birth acgBirth from acg where acg_id = ?";Acg acg = queryForTable(Acg.class,sql2, 2);System.out.println(acg);}
}

测试结果:

Customer{id=1, name='君莫笑', email='yege@qzgs', birth=2035-05-29}
Acg{acgId=2, acgName='苏沐橙', acgEmail='mucheng@)qzgs', acgBirth=2042-02-18}

通用的表的查询操作,用于返回数据表中的多条记录

public class PreparedStatementTest {public <T> List<T> queryForList(Class<T> clazz, String sql, Object ...args){Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {//获得连接conn = JDBCUtils.getConnection();//预编译sql语句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();//创建一个集合,用于存储对象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 columnLabel = rsmd.getColumnLabel(i + 1);//通过反射给customer对象指定的columnClassName属性,赋值为columnValueField field = clazz.getDeclaredField(columnLabel);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;}@Testpublic void queryForListTest(){String sql2 = "select acg_id acgId,acg_name acgName,acg_email acgEmail,acg_birth acgBirth from acg where acg_id < ?";List<Acg> list = queryForList(Acg.class, sql2, 4);for(Acg acg : list){System.out.println(acg);}}
}

测试结果:

Acg{acgId=1, acgName='君莫笑', acgEmail='yege@qzgs', acgBirth=2035-05-29}
Acg{acgId=2, acgName='苏沐橙', acgEmail='mucheng@)qzgs', acgBirth=2042-02-18}
Acg{acgId=3, acgName='黄少天', acgEmail='hualao@qzgs', acgBirth=2038-06-12}

操作BLOB类型字段

MySQL BLOB类型

  • MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
  • 插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的。
  • MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)

MySQL有四种BLOB类型:
  tinyblob:仅255个字符
  blob:最大限制到65K字节
  mediumblob:限制到16M字节
  longblob:可达4GB

  • 实际使用中根据需要存入的数据大小定义不同的BLOB类型。
  • 需要注意的是:如果存储的文件过大,数据库的性能会下降。
  • 如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。

向数据表acg插入Blob类型的数据
public class BlobTest {@Testpublic void insertBlobTest() {Connection conn = null;PreparedStatement ps = null;try {conn = JDBCUtils.getConnection();String sql = "insert into acg(`acg_name`,`acg_email`,`acg_birth`,`acg_photo`) values(?,?,?,?)";ps = conn.prepareStatement(sql);ps.setObject(1,"叶修");ps.setObject(2,"yebuxiu@qzgs");SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");Date date = sdf.parse("2035-05-29");ps.setObject(3,date);FileInputStream fis = new FileInputStream(new File("src\\叶修.gif"));ps.setObject(4,fis);ps.execute();} catch (Exception e) {e.printStackTrace();} finally {JDBCUtils.closeResource(conn,ps);}}
}

执行结果:(找了个动图,它不会不动,hh)

将Blob类型字段的数据,下载下来保存到本地
public class BlobTest {@Testpublic void queryBlobTest() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;InputStream is = null;FileOutputStream fos = null;try {conn = JDBCUtils.getConnection();String sql = "select `acg_id`,`acg_name`,`acg_email`,`acg_birth`,`acg_photo` from acg where `acg_id` = ?";ps = conn.prepareStatement(sql);ps.setInt(1,4);rs = ps.executeQuery();if(rs.next()){int acgId = rs.getInt("acg_id");String acgName = rs.getString("acg_name");String acgEmail = rs.getString("acg_email");Date acgBirth = rs.getDate("acg_birth");Acg acg = new Acg(acgId, acgName, acgEmail, acgBirth);System.out.println(acg);//将blob类型的字段下载下来,以文件的方式保存到本地Blob acgPhoto = rs.getBlob("acg_photo");is = acgPhoto.getBinaryStream();fos = new FileOutputStream(new File("src\\君不笑.gif"));byte[] buffer = new byte[20];int len;while((len = is.read(buffer)) != -1){fos.write(buffer,0,len);}}} catch (Exception e) {e.printStackTrace();} finally {try {if(fos != null)fos.close();} catch (IOException e) {e.printStackTrace();}try {if(is != null)is.close();} catch (IOException e) {e.printStackTrace();}JDBCUtils.closeResource(conn,ps,rs);}}
}

测试结果:

Acg{acgId=4, acgName='叶修', acgeMail='yebuxiu@qzgs', acgBirth=2035-05-29}


更多推荐

PreparedStatement实现对表数据的增删改查操作

本文发布于:2024-02-14 08:35:11,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1762814.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:操作   数据   PreparedStatement

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!