概述
前面已经完成数据库的增删改操作,查询操作需要在前面的基础上使用一个结果集接收执行返回的结果。
使用PreparedStatement好处:
1、解决Statement拼串、sql注入问题
2、可以操作Blob的数据
3、可以实现更高效的批量操作
前提
准备配置文件jdbc.properties
封装连接数据库的基本信息
user=root
password=ad
url=jdbc:mysql://localhost:3306/jdbc
driverClass=com.mysql.cj.jdbc.Driver
准备软件包util
封装连接数据库、关闭资源方法
package util;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**封装数据库连接和关闭*/
public class JDBCUtils {
public static Connection getConnection() throws Exception{
//读取配置文件基本信息
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");
//加载驱动
Class.forName(driverClass);//执行静止代码块
//获取连接
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
}
public static void closeResource(Connection conn, Statement ps, ResultSet rs){
try {
if(ps != null)
ps.close();
}catch (SQLException e){
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
}catch (SQLException e){
e.printStackTrace();
}
try {
if(rs!=null)
rs.close();
}catch (SQLException e){
e.printStackTrace();
}
}
}
一、针对一个SQL语句的查询操作
1、实例化
public static void testQuery1(){
Connection conn = null;//连接
PreparedStatement ps = null;//预编译
ResultSet resultSet = null;//执行后,返回结果集
2、连接数据库
调用前面封装的方法。
try {
//连接数据库
conn = JDBCUtils.getConnection();
3、预编译、填充占位符、执行并返回结果集
executeQuery方法执行;
resultSet保存执行的结果集;
到此,数据库已经执行了传入的sql语句,接下来需要得到数据库执行的结果。
//预编译
String sql = "select id,name,email,birth from customers where id = ?";
ps = conn.prepareStatement(sql);
//填充占位符
ps.setObject(1,1);
//执行并返回结果集
resultSet = ps.executeQuery();
4、处理结果集
resultSet指向的是结果的第一行即列名;
只有一条数据所以使用if即可;
next()方法判断下一条是否有数据,有则返回true,指针指向下一个;
有数据则获取当前数据的各个字段值。
//处理结果集
if(resultSet.next()){//next判断下一条是否有数据,有则返回true,指针指向下一个
//获取当前数据的各个字段值
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);
}
}
创建软件包bean,软件包下创建Customer类
这里使用ORM编程思想:一个数据表对应一个java类;
表中一条记录对应java类的一个对象;
表中的一个字段对应java类的一个属性。
package bean;
import java.util.Date;
/**
ORM编程思想(object relational mapping)
一个数据表对应一个java类
表中的一条记录对应java类的一个对象
表中的一个字段对应java类的一个属性
*/
public class Customer {
private int id;
private String name;
private String email;
private Date birth;
public Customer(){
super();
}
public Customer(int id,String name,String email,Date birth) {
super();
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 +
'}';
}
}
5、关闭资源
调用前面封装的方法。
catch (Exception e){
e.printStackTrace();
}finally {
//关闭资源
JDBCUtils.closeResource(conn,ps,resultSet);
}
}
二、针对一个表的通用的查询操作
与前面不同的是需要传入sql语句和值;
针对Customer表查询,用到前面创建的Customer类。
1、设置方法、参数
/**针对一个表的通用查询*/
public static Customer queryForCustomers(String sql,Object...args){
2、实例化
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
3、连接数据库
try {
//连接
conn = JDBCUtils.getConnection();
4、预编译、填充占位符、执行返回结果集
与针对一条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();
5、处理结果集
由于传入的参数不同,需要通过反射给cust对象指定columnName属性,赋值为columnValue;
通过Customer.class.getDeclaredField(columnName)获取columnName列名的属性;
属性可能是私有,需要setAccessible()方法确保属性可访问;
将cust中的columnName属性赋值为columnValue
(注意:Customer中的属性名如果与数据库中的字段名不同,则查询时可以给字段名起别名,别名为Customer中的属性名)
//处理结果集
if(rs.next()){
Customer cust = new Customer();
//处理结果集一行数据的每一列
for(int i = 0;i<columnCount;i++){
Object columValue = rs.getObject(i+1);//获取列值
String columnName = rsmd.getColumnLabel(i+1);//获取每个列的别名,没有别名则获取原名
//给cust对象指定columnName属性,赋值为columValue,反射
Field field = Customer.class.getDeclaredField(columnName);
field.setAccessible(true);
field.set(cust,columValue);
}
return cust;
}
}
6、关闭资源
catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,ps,rs);
}
return null;
}
三、针对不同表的通用的查询操作(返回一条记录)
与上一个不同的是需要传入不同的类;
使用泛型T表示传入的类;
使用时,传入类、sql语句、和对应值即可。
1、创建泛型方法,设置参数
public static <T> T getInstance(Class<T> clazz,String sql,Object... args){
2、实例化
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
3、连接数据库
try {
conn = JDBCUtils.getConnection();
4、预编译、填充占位符、执行返回结果集
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();
5、处理结果集
利用泛型动态创建对象
if (rs.next()) {
T t = clazz.newInstance();//创建对象,弱类型效率低,只能无参
for(int i = 0;i<columnCount;i++){
Object columValue = rs.getObject(i+1);
String columnLabel = rsmd.getColumnLabel(i+1);
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columValue);
}
return t;
}
}
6、关闭资源
catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,ps,rs);
}
return null;
}
四、针对不同表的通用的查询操作(返回多条记录)
与上一个不同的是使用while创建对象,将对象对存入一个集合里,再将集合返回;
调用时循环输出。
1、创建泛型方法,设置参数
public static <T> List<T> getInstance2(Class<T> clazz, String sql, Object... args){
2、实例化
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
3、连接数据库
try {
conn = JDBCUtils.getConnection();
4、 预编译、填充占位符、执行返回结果集
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();
5、处理结果集
//创建集合对象
ArrayList<T> list = new ArrayList<T>();
while(rs.next()) {
T t = clazz.newInstance();//创建对象,弱类型效率低,只能无参
for(int i = 0;i<columnCount;i++){
Object columValue = rs.getObject(i+1);
String columnLabel = rsmd.getColumnLabel(i+1);
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columValue);
}
list.add(t);
}
return list;
}
6、关闭资源
catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,ps,rs);
}
return null;
}
调用示例
String sql1 = "select id,name,birth,email from customers where id < ?";
List<Customer> list = getInstance2(Customer.class,sql1,12);
list.forEach(System.out::println);
总结
ORM思想(object relational mapping):1、一个数据表对应一个java类
2、表中一条记录对应java类的一个对象
3、表中一个字段对应java类的一个属性
JDBC结果集的元数据:ResultSetMetaData
获取列数:getColumnCount()
获取列的别名:getColumnLabel()
反射:通过反射,创建指定类的对象,获取指定的属性并赋值
最后
以上就是高高大雁为你收集整理的【JDBC】-- PreparedStatement实现数据库查询操作前提一、针对一个SQL语句的查询操作 二、针对一个表的通用的查询操作三、针对不同表的通用的查询操作(返回一条记录)四、针对不同表的通用的查询操作(返回多条记录)总结的全部内容,希望文章能够帮你解决【JDBC】-- PreparedStatement实现数据库查询操作前提一、针对一个SQL语句的查询操作 二、针对一个表的通用的查询操作三、针对不同表的通用的查询操作(返回一条记录)四、针对不同表的通用的查询操作(返回多条记录)总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复