使用PreparedStatement实现增、删、改操作
创建一个customers表
-- 创建一个customers表
CREATE TABLE IF NOT EXISTS `customers` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(15) DEFAULT NULL,
`email` varchar(20) DEFAULT NULL,
`birth` date DEFAULT NULL,
`photo` mediumblob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=gb2312;
添加数据
INSERT INTO `customers` (`id`, `name`, `email`, `birth`, `photo`) VALUES
(1, '汪峰', 'wf@126.com', '2010-02-02', NULL),
(2, '王菲', 'wangf@163.com', '1988-12-26', NULL),
(3, '林志玲', 'linzl@gmail.com', '1984-06-12', NULL),
(4, '汤唯', 'tangw@sina.com', '1986-06-13', NULL),
(5, '成龙', 'Jackey@gmai.com', '1955-07-14', NULL),
(6, '迪丽热巴', 'reba@163.com', '1983-05-17', NULL),
(7, '刘亦菲', 'liuyifei@qq.com', '1991-11-14', NULL),
(8, '陈道明', 'bdf@126.com', '2014-01-17', NULL),
(10, '周杰伦', 'zhoujl@sina.com', '1979-11-15', NULL),
(12, '黎明', 'LiM@126.com', '1998-09-08', NULL),
(13, '张学友', 'zhangxy@126.com', '1998-12-21', NULL),
(16, '朱茵', 'zhuyin@126.com', '2014-01-16',null),
(18, '贝多芬', 'beidf@126.com', '2014-01-17', NULL);
创建成功
在java中实现:
运行:
java.lang.classCastException: java.util.Date cannot be cast to java.sql.Date Java.lang.classCastException:java.util.Date不能转换为java.sql.Date。
类型转换有歧义,出现了两个Date,一个java.util.Date,一个java.sql.Date,所以会报错,解决方法也很简单,将第一个Date取消指定类型,第二个Date指定java.sql.Date即可
添加成功!
完整代码:
// 向表中添加一条记录
@Test
public void testInsert() throws Exception {
// 1.反射读取配置文件
InputStream is = JDBCdemo.class.getClassLoader().getResourceAsStream("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.获取连接
Connection conn = DriverManager.getConnection(url, user, password);
//5.预编译sql语句,返回PreparedStatementTest的实例
String sql = "insert into customers(name, email, birth)values(?,?,?)";
//?是占位符
PreparedStatement ps = conn.prepareStatement(sql);
// 6.填充占位符
ps.setString(1, "杨戬");
ps.setString(2, "yangjian@123.com");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("0896-06-26");
ps.setDate(3, new java.sql.Date(date.getTime()));
//7.执行操作
ps.execute();
// 8.资源的关闭
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() throws Exception {
//1.获取数据库的连接
Connection conn = JDBCUtils.getConnection();
//2.预编译sql语句,返回Preparedstatement的实例
String sql = "update customers set name = ? where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
//3.填充占位符
ps.setObject(1,"杨丽萍");
ps.setObject(2,3);
//4.执行
ps.execute();
//5.资源的关闭
JDBCUtils.closeResource(conn,ps);
System.out.println("修改成功!");
}
通用的增删改
// 通用的增删改操作
public void update(String sql,Object ... args){//sql中占位符的个数与可变形参的长度一致
Connection conn = null;
PreparedStatement ps = null;
try {
//1.获取数据库的连接
conn = JDBCUtils.getConnection();
//2.获取PreparedStatement的实例 (或:预编译sql语句)
ps = conn.prepareStatement(sql);
//3.填充占位符
for(int i = 0;i < args.length;i++){
ps.setObject(i + 1, args[i]);
// i + 1:mysql从1开始
// args[i]:数组从0开始,不用加1
}
//4.执行sql语句
ps.execute();
} catch (Exception e) {
e.printStackTrace();
}finally{
//5.关闭资源
JDBCUtils.closeResource(conn, ps);
}
}
测试:
@Test //测试一下
public void testUpdate2(){
String sql = "delete from customers where id = ?";
update(sql,6);
}
删除前:
删除后:6被删除了
针对Customers表的查询
package com.jdbc.test2;
import com.Util.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* @author 乱码酱
* @date :2022-09-21 19:25
* @program: JDBC
* @create:对Customers表的查询
*/
public class CustomersQuery {
// 针对Customers表的查询
@Test
public void testQuery1() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
try {
//1.获取数据库的连接
conn = JDBCUtils.getConnection();
//2.获取PreparedStatement的实例 (或:预编译sql语句)
String sql = "select id, name, email, birth from customers where id = ?";
ps = conn.prepareStatement(sql);
ps.setObject(1,1);
//3.执行并返回结果集
resultSet = ps.executeQuery();
//4.处理结果集
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);
// 方法1:字符串拼接
System.out.println("id = " + id + ",name = " + name + ", email = " + email + ", birth =" + birth);
System.out.println("------------------");
// 方法2:封装在数组中
Object[] data = new Object[]{id, name, email, birth};
for(int i=0;i<data.length;i++) {
System.out.println(data[i]);
}
System.out.println("------------------");
// 方法3:封装在类的对象中(推荐)
Customers c = new Customers(id, name, email, birth);
System.out.println(c);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭资源
JDBCUtils.closeResource(conn, ps, resultSet);
}
}
}
ORM编程思想(object relational mapping)对象关系映射
* 一个数据表对应一个java类
* 表中的一条记录对应java类的一个对象
* 表中的一个字段对应java类的一个属性
package com.jdbc.test2;
import java.sql.Date;
/**
* @author 乱码酱
* @date :2022-09-21 20:09
* @program: JDBC
* @create:结果封装在类的对象中(这是创建的类)
*
* ORM编程思想(object relational mapping)对象关系映射
* 一个数据表对应一个java类
* 表中的一条记录对应java类的一个对象
* 表中的一个字段对应java类的一个属性
*/
public class Customers {
private int id;
private String name;
private String email;
private Date birth;
public Customers() {
}
public Customers(int id, String name, String email, Date birth) {
this.id = id;
this.name = name;
this.email = email;
this.birth = birth;
}
@Override
public String toString() {
return "Customers{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", birth=" + birth +
'}';
}
}
查询结果:
id = 1,name = 汪峰, email = wf@126.com, birth =2010-02-02
------------------
1
汪峰
wf@126.com
2010-02-02
------------------
Customers{id=1, name='汪峰', email='wf@126.com', birth=2010-02-02}
测试针对Customers表的通用查询操作时报错 java.lang.NoSuchFieldException: jdbc 表示该类没有指定名称的字段
有时候使用反射进行Field相关操作的时候会出现这样异常,一般原因有两种:
1.本身就没有该Field;
2.有该Field,但是该Field是使用private修饰的,而在获取该Field的时候,需要使用getDeclaredField这个方法。
查看数据库customers表,对应字段有
查看Customers类也有对应字段
后来检查一看,好家伙,测试方法和方法同名了
改了以后依旧是同样的问题,找过许多可能,包括字段命名包含空格、调用的方法、甚至将Customers类的属性从private改为public也是同样报错,后来真相大白了——调用的函数出错
getCatalogName()方法是
Gets the catalog name for the table that includes the designated column. 获取包含指定列的表的目录名称。
通用的针对Order表的查询操作
针对于表的字段名与类的属性名不相同的情况: * 1。必须声明sql时,使用类的属性名来命名字段的别名 * 2.使用ResultSetMetaData时,需要使用getColumnLabel()来昔换getColumnName(),获取列的别名。 * 说明:如果sq1中没有给字段其别名,getColumnLabel()获取的就是列名
java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
提供有关数据库访问错误或其他错误的信息的异常。
package com.jdbc.test3;
import com.Util.JDBCUtils;
import com.jdbc.test2.Customers;
import org.junit.Test;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/**
* @author 乱码酱
* @date :2022-09-22 11:00
* @program: JDBC
* @create:通用的针对Order表的查询操作
*/
public class OrderForQuery {
@Test
public void testOrderForQuery(){
String sql ="select order_id orderId, order_name orderName, order_date orderDate from `order` where orderId = ? ";
Order order = orderForQuery(sql, 1);
System.out.println(order);
}
public Order orderForQuery(String sql, Object...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1.获取数据库的连接
conn = JDBCUtils.getConnection();
//2.预编译sql语句
ps = conn.prepareStatement(sql);
//填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
//3.执行并返回结果集
rs = ps.executeQuery();
//获取结果集的元数据ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数(字段数)
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
Order order = new Order();
// 处理结果集一行数据中的每一列
for (int i = 0; i < columnCount; i++) {
//获取列值:通过ResultSet
Object columnValue = rs.getObject(i + 1);
//获取每个类的列名
String columnName = rsmd.getColumnName(i + 1);
//通过反射,将对象指定名columnName属性赋值为columValue:
Field field = Order.class.getDeclaredField(columnName);
field.setAccessible(true); //里面可能有私有属性,暴力反射
field.set(order, columnValue);
}
return order;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,ps,rs);
}
return null;
}
}
Order类:
package com.jdbc.test3;
import java.sql.Date;
/**
* @author 乱码酱
* @date :2022-09-22 10:59
* @program: JDBC
* @create:Order类
*/
public class Order {
private int orderId;
private String orderName;
private Date orderDate;
public Order() {
}
public Order(int orderId, String orderName, Date orderDate) {
this.orderId = orderId;
this.orderName = orderName;
this.orderDate = orderDate;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", orderName='" + orderName + '\'' +
", orderDate=" + orderDate +
'}';
}
}
SQLSyntaxErrorException 当SQLState类值为“ 42 ”时,或者在供应商指定的条件下,抛出SQLException的子类。 这表示正在进行的查询违反了SQL语法规则。
破案了,真相是查询语句之前的查找字段orderld是错的,改名是在查询时结果集上改但是原表还是沿用order_id:
String sql ="select order_id orderId, order_name orderName, order_date orderDate from `order` where oderId = ? "; × String sql ="select order_id orderId, order_name orderName, order_date orderDate from `order` where order_id = ? "; √
ORM编程思想(object relational mapping)对象关系映射
* 一个数据表对应一个java类
* 表中的一条记录对应java类的一个对象
* 表中的一个字段对应java类的一个属性
获取列数:int columnCount = rsmd.getColumnCount();
获取列值:Object columnValue = resultSet.getObject(int index);
获取列的别名∶ String columnLabel = rsmd.getColumnLabel(int index);
借助反射给Order order = new Order()方式创建的对象的指定属性赋值
使用PreparedStatement实现针对不同表的通用查询操作
返回一条查询数据
因为字段有下划线,所以查询要记得改名
完整代码:
package com.jdbc;
import com.Util.JDBCUtils;
import com.jdbc.test2.Customers;
import com.jdbc.test3.Order;
import org.junit.Test;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/**
* @author 乱码酱
* @date :2022-09-22 16:34
* @program: JDBC
* @create:使用PreparedStatement实现针对不同表的通用查询操作
*/
public class PreparedStatementQuery {
@Test
public void testGetInstance(){
String sql = "select id, name, email from customers where id = ?";
Customers c = getInstance(Customers.class, sql, 19);
System.out.println(c);
String sql1= "select order_id orderId, order_name orderName from `order` where order_id = ?";
Order o = getInstance(Order.class, sql1, 1);
System.out.println(o);
}
public <T> T getInstance(Class<T> clazz,String sql, Object...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = 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.执行executeQuery(),并返回结果集ResultSet
rs = ps.executeQuery();
//5.获取结果集的元数据ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数(字段数)
// 6.通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
T t = clazz.newInstance();
// 遍历处理结果集一行数据中的每一列
for (int i = 0; i < columnCount; i++) {
//获取列值
Object columValue = rs.getObject(i + 1);
//获取每个类的列名
// String columName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
//给cust对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true); //里面可能有私有属性,暴力反射
field.set(t, columValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
}
返回多条查询语句
forEach()
list.forEach(System.out::println); //默认方法,实现遍历输出
@Test // 返回多条查询语句
public void testGetForList(){
String sql = "select id,name,email from customers where id < ?";
List<Customers> list = getForList(Customers.class,sql,12);
list.forEach(System.out::println); //默认方法,实现遍历输出
String sql1 = "select order_id orderId,order_name orderName from `order` where order_id < ?";
List<Order> orderList = getForList(Order.class, sql1,5);
orderList.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 {
//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.执行executeQuery(),并返回结果集ResultSet
rs = ps.executeQuery();
//5.获取结果集的元数据ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数(字段数)
// 6.通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值
int columnCount = rsmd.getColumnCount();
// 创建集合对象
ArrayList<T> list = new ArrayList<T>();
while (rs.next()) {
T t = clazz.newInstance();
// 遍历处理结果集一行数据中的每一列:给T对象指定的属性赋值
for (int i = 0; i < columnCount; i++) {
//获取列值
Object columValue = rs.getObject(i + 1);
//获取每个类的列名
// String columName = rsmd.getColumnName(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
//给cust对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true); //里面可能有私有属性,暴力反射
field.set(t, columValue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}