JDBC(1)—Mysql数据库的增删改查(工具类通用)

本文详细介绍如何使用Java进行数据库连接及增删改查操作,包括配置文件读取、PreparedStatement使用、结果集处理等关键技术。


前言

Mysql 8.0

提示:以下是本篇文章正文内容,下面案例可供参考

一、数据库的连接

  1. 读取配置文件中的4个基本信息
    1.1 加载配置文件
    通过getClassLoader()获取该字节码文件对应的类加载器,并获取指定文件的一个字节流 InputStream
    1.2 创建Properties对象,load() 方法加在配置文件,读取配置信息
  2. 加载驱动
  3. 获取连接

准备配置文件 jdbc.properties,此配置文件放在工程目录

# 数据库连接的4个基本要素(user,password,url,driverClasss)
user=root
password=aa1234
# 以下是mysql 8 的连接方式
url=jdbc:mysql://localhost/student?serverTimezone=UTC
driverClass=com.mysql.cj.jdbc.Driver
# 以下是mysql 5 的连接方式
#url=jdbc:mysql://localhost:3306/student?rewriteBatchedStatements=true
#driverClass=com.mysql.jdbc.Driver

测试:

import org.junit.Test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

/**
 * 数据库的连接
 * @Author: junxiang
 */
public class  ConnectionTest {

    // 将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接
    /*
     * 此种方式的好处:
     * 1.实现了数据与代码的分离。实现了解耦
     * 2.如果需要修改配置文件信息,可以避免程序重新打包。
     */
    @Test
    public void getConnection() throws Exception{

        //1.读取配置文件中的4个基本信息
        // 1.1 加载配置文件
        // getClassLoader()获取该字节码文件对应的类加载器,方便加载进内存
        // 获取指定文件的一个字节流 InputStream
        ClassLoader classLoader = ConnectionTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc.properties");

        // 创建Properties对象
        // load() 方法加在配置文件,传进去一个 InputStream/inStream/Reader/reader 对象
        Properties pros = new Properties();
        pros.load(is);

        // 1.2 读取配置信息
        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 conn = DriverManager.getConnection(url, user, password);
        System.out.println(conn);
	
    }

}

二、数据库的CRUD(增删改查)

创建customers表

DROP TABLE IF EXISTS `customers`;

CREATE TABLE `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;

创建Customer类与数据库中表customers对应

import java.sql.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 + "]";
	}

}

在这里插入图片描述

创建工具类

工具类封装了数据库的连接与资源的释放方法

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

/**
 * 
 * @Description 操作数据库的工具类
 * @Author: junxiang
 * 
 */
public class JDBCUtils {
	
	/**
	 * 
	 * @Description 获取数据库的连接
 	 * @Author: junxiang
	 * @return Connection
	 * @throws Exception
	 */
	public static Connection getConnection() throws Exception {
		// 1.读取配置文件中的4个基本信息
		ClassLoader classLoader = ConnectionTest.class.getClassLoader();
        InputStream is = classLoader.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 conn = DriverManager.getConnection(url, user, password);
		return conn;
	}
	/**
	 * 
	 * @Description 关闭连接和Statement的操作
 	 * @Author: junxiang
	 * @param conn
	 * @param ps
	 */
	public static void closeResource(Connection conn,PreparedStatement ps){
		try {
			if(ps != null)
				ps.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if(conn != null)
				conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 
	 * @Description 关闭资源操作
 	 * @Author: junxiang
 	 * @Date: 2021/3/08 19:39
	 * @param conn Connection 对象
	 * @param ps   PreparedStatement 对象
	 * @param rs   ResultSet 对象(结果集)
	 */
	public static void closeResource(Connection conn,PreparedStatement 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();
		}
	}
}

通用的增删改方法

  1. 获取数据库的连接
  2. 预编译sql语句,返回PreparedStatement的实例
  3. 填充占位符
  4. 执行SQL操作
  5. 释放资源
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Properties;

import jdbc.preparedstatement.util.JDBCUtils;
import org.junit.Test;


/**
 * 
 * @Description 
 * 使用PreparedStatement来替换Statement,实现对数据表的增删改操作
 * @Author: junxiang
 * 
 */

public class PreparedStatementUpdateTest {
	
	@Test
	public void testCommonUpdate(){
		// insert
//		String sql = "insert into customers(name,email,birth) values(?,?,?)"; // ? -> 占位符
//		int oper = update(sql, "李四", "lisi@126.com", "1999-09-10");

		// update
//		String sql = "update customers set email = ? where id = ?";
//		int oper = update(sql, "lisi@qq.com", "27");

		// delete
		String sql = "delete from customers where id = ?";
		int oper = update(sql, 27);
		if(oper > 0 ){
			System.out.println("操作成功!");
		}else {
			System.out.println("操作失败!");
		}

	}

	/**
	 * 通用的增删改操作
	 * @param sql
	 * @param args
	 * @return
	 */
	//sql中占位符的个数与可变形参的长度相同!
	public int update(String sql,Object ...args){
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.获取数据库的连接
			conn = JDBCUtils.getConnection();
			//2.预编译sql语句,返回PreparedStatement的实例
			// 预编译已经把sql的逻辑给确定,之后填充的占位符(?,?,?)只认为是数据
			ps = conn.prepareStatement(sql);
			//3.填充占位符
			for(int i = 0;i < args.length;i++){
				/*
				 * @param parameterIndex the first parameter is 1, the second is 2, ...
				 * @param x the object containing the input parameter value
				 */
				ps.setObject(i + 1, args[i]);//小心参数声明错误!!
			}
			//4.执行
			/*
			 * ps.execute():
			 * 如果执行的是查询操作,有返回结果,则此方法返回true;
			 * 如果执行的是增、删、改操作,没有返回结果,则此方法返回false.
			 */
			//方式一:
//			return ps.execute();
			//方式二:int executeUpdate()
			return ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//5.资源的关闭
			JDBCUtils.closeResource(conn, ps);
			
		}
		return 0;
	}
}

通用的查方法

  1. 获取数据库的连接
  2. 预编译sql语句,返回PreparedStatement的实例
  3. 填充占位符
  4. 执行SQL操作,获取结果集
    rs = ps.executeQuery();
  5. 通过结果集获取结果集的元数据
    ResultSetMetaData rsmd = rs.getMetaData();
  6. 通过ResultSetMetaData获取结果集中的列数
    int columnCount = rsmd.getColumnCount();
  7. 读取并处理数据库中数据,封装成对应的类对象 t
    7.1 理结果集一行数据中的每一个列
    7.2 获取列值及每个列的列名
    7.3 通过反射,给t对象指定的columnName属性,赋值为columValue
  8. 打印查询结果
  9. 释放资源
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

import jdbc.preparedstatement.bean.Customer;
import jdbc.preparedstatement.bean.Order;
import jdbc.preparedstatement.util.JDBCUtils;
import org.junit.Test;

/**
 * 
 * @Description 数据库通用的 查: 查询不同表的数据
 * @Author: junxiang
 * 
 */

public class PreparedStatementQueryTest {
	
	@Test
	public void testGetForList(){
		
		String sql = "select id,name,email from customers where id < ?";
		List<Customer> list = getForList(Customer.class,sql,12);
		list.forEach(System.out::println);
		
		String sql1 = "select order_id orderId,order_name orderName from `order`";
		List<Order> orderList = getForList(Order.class, sql1);
		orderList.forEach(System.out::println);
	}
	/**
	 * 定义泛型方法
	 * @param clazz
	 * @param sql
	 * @param args
	 * @param <T>
	 * @return
	 */
	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
			ResultSetMetaData rsmd = rs.getMetaData();
			// 通过ResultSetMetaData获取结果集中的列数
			int columnCount = rsmd.getColumnCount();
			//创建集合对象
			ArrayList<T> list = new ArrayList<T>();
			while (rs.next()) {
				// 方式1:通过Class 对象 t 中的newInstance() 直接创建对象
				T t = clazz.newInstance();
				// 方式2:先获取构造器,然后再创建对象
				// T t1 = clazz.getConstructor().newInstance();
				// T t2 = clazz.getDeclaredConstructor().newInstance();
				
				// 处理结果集一行数据中的每一个列:给t对象指定的属性赋值
				for (int i = 0; i < columnCount; i++) {
					// 获取列值
					Object columValue = rs.getObject(i + 1);

					// 获取每个列的列名
					// String columnName = rsmd.getColumnName(i + 1);
					// 获取每个列的列名或别名
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 给t对象指定的columnName属性,赋值为columValue:通过反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columValue);
				}
				// 将每个 对象加入到List中
				list.add(t);
			}
			
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(conn, ps, rs);
		}
		return null;
	}
}

总结

  1. 本文使用读取配置文件方式连接Mysql,并用一个Java类对表进行映射,将表的字段封装成类的属性:
    1.1 一个数据表对应一个java类
    1.2 表中的一条记录对应java类的一个对象
    1.3 表中的一个字段对应java类的一个属性
  2. 用Statement 的子接口PreparedStatement 接口来操作数据表,即调用 Connection 对象的 preparedStatement(String sql)方法获取 PreparedStatement 对象,它表示一条预编译过的 SQL 语句,用占位符? 来表示SQL 语句中的参数,setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值,第二个参数可以是一个可变长参数
  3. 用ResultSetMetaData获取关于 ResultSet 对象中列的类型和属性信息的对象(即获取结果集的元数据 :ResultSetMetaData),ResultSetMetaData rsmd= rs.getMetaData()
  4. 运用了Java反射的知识
    4.1 在读取配置文件中使用getClassLoader()获取该字节码文件对应的类加载器,从而获取指定文件的一个字节流 InputStream
    4.2 在 的操作时,通过Class 对象 t 中的newInstance() 直接创建对象(也可以先获取构造器,在创建对象)
    4.3 当获取到数据库中列名及列值时,通过类对象的方法getDeclaredField()获取类的属性,并调用set()方法给刚刚获取到的属性赋值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值