JDBC学习笔记——获取连接、PreparedStatement、Blob、批处理

一、获取连接

工程文件夹下
在这里插入图片描述

package jdbc_1.connection;

import java.io.*;
import java.sql.*;
import java.util.Properties;

import org.junit.Test;

public class ConnectionTest {
	//连接方式1
	@Test
	public void testConnection1() throws Exception {
		//com.mysql.cj.jdbc.Driver类实现Driver接口
		Driver driver = new com.mysql.cj.jdbc.Driver();
		
		/* 
		 * URL:
		 * http://localhost:8080/gmail/123.jpg
		 * jdbc:mysql:协议
		 * localhost:: IP地址
		 * 3306:MySQL默认端口
		 * test:数据库名
		 * ?serverTimezone=UTC:使用Mysql Connector/J 6.x以上的版本,会报时区错误,要添加改语句
		 */
		String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
		
		//将用户名和密码封装在Properties中
		Properties info = new Properties();
		info.setProperty("user", "root");
		info.setProperty("password", "macheng_0213");
		
		//使用Driver对象调用connect()方法,获取Connection对象
		Connection conn = driver.connect(url, info);

	}
	
	//方式2:目的是在程序中不出现第三方API,使得程序具有较好的可移植性
	@Test
	public void testConnection2() throws Exception{
		//1.获取Driver实现类对象,通过反射实现
		Class clazz = Class.forName("com.mysql.cj.jdbc.Driver");
		Driver driver = (Driver)clazz.getConstructor().newInstance();
		
		//2.提供要连接的数据库,即URL
		String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
		
		//3.提供所连数据库的用户名和密码
		Properties info = new Properties();
		info.setProperty("user", "root");
		info.setProperty("password", "macheng_0213");
		
		//4.获取连接
		Connection conn = driver.connect(url, info);
	
	}
	
	//方式3:使用DriverManager替换Driver
	@Test
	public void testConnection3() throws Exception{
		//(1)提供3个获取链接的基本信息
		String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
		String user = "root";
		String password = "macheng_0213";
				
		//(2)获取Driver实现类对象,通过反射实现
		Class clazz = Class.forName("com.mysql.cj.jdbc.Driver");
		Driver driver = (Driver)clazz.getConstructor().newInstance();
		
		//1.注册驱动
		DriverManager.registerDriver(driver);
			
		//2.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);
		
	}
	
	//方式4:可以通过反射隐式加载驱动,而不用显示注册驱动了
	@Test
	public void testConnection4() throws Exception{
		//1.提供3个获取链接的基本信息
		String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
		String user = "root";
		String password = "macheng_0213";
				
		//2.加载Driver
		//com.mysql.cj.jdbc.Driver在加载时会自动注册驱动
		Class.forName("com.mysql.cj.jdbc.Driver");
//		Driver driver = (Driver)clazz.getConstructor().newInstance();
		
//		//1.注册驱动
//		DriverManager.registerDriver(driver);
		
		/*
		 * 为什么可以省略注册驱动的步骤?
		 * 因为在MySQL的Driver实现类中声明了如下操作,该静态代码块会随着反射
		 * Class.forName("com.mysql.cj.jdbc.Driver");的加载而加载,因此可以省略
		 * 	static {
				try {
					java.sql.DriverManager.registerDriver(new Driver());
				} catch (SQLException E) {
					throw new RuntimeException("Can't register driver!");
				}
			}
		 */
		
		//3.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);

	}
	
	//方式5:最终版 将数据库连接需要的4个基本信息声明在配置文件中,通过读取文件的方式获取连接
	/*
	 * 好处:
	 * 1.实现了代码与数据的分离(解耦)
	 * 2.如果需要修改配置文件信息,可以避免程序重新打包,只需更换配置文件即可
	 */
	@Test
	public void testConnection_final() throws Exception{
		//1.声明配置文件,要声明在src文件下
		
		//2.读取配置文件中的4个基本信息
		//通过io流读取
//		FileInputStream in = new FileInputStream(
//				new File("D:\\Java\\eclipse\\workplace\\myJDBC\\src\\jdbc.properties"));
		//通过类加载器读取
		InputStream in = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
		//创建properties对象读取数据
		Properties prop = new Properties();
		prop.load(in);
		
		String user = prop.getProperty("user");
        String password = prop.getProperty("password");
        String url = prop.getProperty("url");
        String driverClass = prop.getProperty("driverClass");
				
		//3.加载Driver
		Class.forName(driverClass);

		//4.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);

	}
		
}

二、PreparedStatement

增删改

package jdbc_1.preparedStatement;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import org.junit.Test;

/**
 * 使用PreparedStatement替换Statement,实现对数据表的增删改查操作
 * 
 * 增删改查(CRUD): 增删改不需要返回结果,查需要返回结果集
 * 
 * @author MCC
 *
 */
public class PreparedStatementInsertTest {
	// 向customers表中添加记录
	@Test
	public void insert() {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.4个基本信息
			InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
			Properties prop = new Properties();
			prop.load(in);
			String user = prop.getProperty("user");
			String password = prop.getProperty("password");
			String url = prop.getProperty("url");
			String driverClass = prop.getProperty("driverClass");
			
			//2.加载驱动
			Class.forName(driverClass);
			
			//3.获取连接
			conn = DriverManager.getConnection(url, user, password);
			
			//4.预编译sql语句,获取PreparedStatement对象
			/*
			 * ? 占位符
			 */
			String sql = "insert into customers (name, email, birth) values (?, ?, ?)";
			ps = conn.prepareStatement(sql);
			
			//5.填充占位符,与数据库相关的索引从1开始
			ps.setString(1, "哪吒");
			ps.setString(2, "nezha@gmail.com");
			
			//保证生日的格式正确
			//(1)定义日期格式
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			//(2)传入日期
			Date date = sdf.parse("1999-1-1");
			//(3)传入数据
			ps.setDate(3, new java.sql.Date(date.getTime()));

			//6.执行sql语句
			ps.execute();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//7.关闭资源
			try {
				if(ps != null) {
					ps.close();
				}
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			try {
				if(conn != null) {
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
	}
}

package jdbc_1.preparedStatement;

import java.sql.Connection;
import java.sql.PreparedStatement;

import org.junit.Test;

import jdbc_1.myutil.*;

public class PreparedStatementUpdateTest {
	@Test
	//修改customer表中的记录
	public void update() {
		Connection conn = null;
		PreparedStatement ps = null;
		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.setInt(2, 18);
					
			//4.执行
			ps.execute();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//5.关闭资源
			JDBCUtils.closeResource(ps, conn);
		}		
				
	}
}

ResultSet接收查询结果

Bean类

Class Customer

package jdbc_1.bean;

import java.sql.Date;

/**
 * 用来存储从customer表中查询到的数据
 * 
 * ORM编程思想:Object Relational mapping对象关系映射
 * 一个数据表对应一个java类,表中的一个字段对应类中的一个属性,每一条数据对应类的一个对象
 * 
 * @author MCC
 *
 */
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 + "]";
	}
	
}

Class Order

package jdbc_1.bean;

import java.sql.Date;

/**
 * 用来存储从order表中查询到的数据
 * @author MCC
 *
 */
public class Order {
	private int orderId;
	private String orderName;
	private Date orderDate;
	
	public Order() {
		super();
	}

	public Order(int orderId, String orderName, Date orderDate) {
		super();
		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 + "]";
	} 
	
}

customer表

package jdbc_1.preparedStatement;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import org.junit.Test;

import jdbc_1.bean.Customer;
import jdbc_1.myutil.JDBCUtils;

/**
 * 针对于customers表的查询操作
 * @author MCC
 *
 */
public class SelectCustomerTest {
	/*
	 * 演示查询customer表
	 */
	@Test
	public void testSelectCustomers() {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			//1.获取连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译,返回PreparedStatement实例
			String sql = "select id, name, email, birth from customers where id = ?";
			ps = conn.prepareStatement(sql);
			
			//3.填充占位符
			ps.setInt(1, 1);
			
			//4.执行语句,返回结果集
			rs = ps.executeQuery();
			
			//5.处理结果集
			/*
			 * next():
			 * 判断结果集中的下一条是否有数据,如果有返回true,并将指针下移一位(初始时指针位于数据前一位)
			 */
			if(rs.next()) {
				//获取当前这条数据的各个字段的值
				int id = rs.getInt(1);
				String name = rs.getString(2);
				String email = rs.getString(3);
				Date birth = rs.getDate(4);
				
				//显示信息
				//方式1
//			System.out.println(
//					"id = " + id + " name = " + name + " email = " + email + " birth " + birth);
				
				//方式2
//			Object[] data = new Object[]{id, name, email, birth};
				
				//方式3:将信息存储到Customer对象中
				Customer customer = new Customer(id, name, email, birth);
				System.out.println(customer);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//6.关闭资源
			JDBCUtils.closeResource(rs, ps, conn);
		}
		
	}
	
	/*
	 * 针对于customers表的通用操作
	 */
	public Customer testGengralCustomers(String sql, Object ...obj) {
		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<obj.length; i++) {
				ps.setObject(i+1, obj[i]);
			}
			
			//4.执行,获取ResultSet实例
			rs = ps.executeQuery();
			
			//5.判断是否有数据,并存入Customer对象中
			/*
			 * 要知道查出的数据有几个字段,才能定义变量接收数据,
			 * 获取字段数的方法封装在数据集元数据ResultSetMetaData中,
			 * 所以先使用ResultSet对象调用getMetaData()方法获取
			 */
			//获取结果集的元数据
			ResultSetMetaData rsmd = rs.getMetaData();
			
			//获取结果集的字段(列)数
			int count = rsmd.getColumnCount();
			
			if(rs.next()) {
				Customer customer = new Customer();
				//处理结果集中每一行数据中的每一列
				for(int i=0; i<count; i++) {
					//获取结果集每列的值
					Object columnValue = rs.getObject(i+1);
					//获取结果集每列的列名
					String columnName = rsmd.getColumnName(i+1);
					//给customer对象的columnName属性赋值为columnValue
					//通过反射完成
					//获取Customer类的名称为columnName的属性
					Field field = Customer.class.getDeclaredField(columnName);
					//将该属性设置为可访问
					field.setAccessible(true);
					//将当前customer对象的columnName属性赋值为columnValue
					field.set(customer, columnValue);
					
				}
				return customer;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(rs, ps, conn);
		}
		return null;
	}
	
	@Test
	public void testGenCustomers() {
		String sql1 = "select id, name, email, birth from customers where id = ?";
		String sql2 = "select name, email from customers where name = ?";
		Customer customer1 = testGengralCustomers(sql1, 13);
		Customer customer2 = testGengralCustomers(sql2, "周杰伦");
		System.out.println(customer1);
		System.out.println(customer2);
	}
	
}

Order表

package jdbc_1.preparedStatement;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

import org.junit.Test;

import jdbc_1.bean.Order;
import jdbc_1.myutil.JDBCUtils;

/**
 * 演示对Order表的通用查询操作
 * @author MCC
 *
 */
public class SelectOrderTest {
	@Test
	public void testGenOrder() {
		/*
		 * 当类的属性名与表的字段名不一致时,需要给表的各个字段起别名,别名为对应的属性名,
		 * rsmd.getColumnName()方法获取的是表的字段名(即原始名),不是别名,
		 * 因此此时需要更改该方法,使用rsmd.getColumnLabel()方法则可以获取字段的别名
		 */
		String sql = 
				"select "
				+ "order_id orderId, "
				+ "order_name orderName, "
				+ "order_date orderDate "
				+ "from `order` where order_id = ?";
		Order order = testGengralOrder(sql, 4);
		System.out.println(order);
	}
	
	public Order testGengralOrder(String sql, Object ...obj) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			//1.建立连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译sql语句
			ps = conn.prepareStatement(sql);
			
			//3.填充占位符
			for(int i=0; i<obj.length; i++) {
				ps.setObject(i+1, obj[i]);
			}
			
			//4.执行sql,获取结果集对象以及结果集元数据对象
			rs = ps.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			if(rs.next()) {//如果有数据,则取出数据
				Order order = new Order();
				//根据数据的字段数,判断取出次数
				int columnCount = rsmd.getColumnCount();
				for(int i=0; i<columnCount; i++) {
					//取出数值以及列名
					/*
					 * 获取列的列名:rsmd.getColumnName()——不推荐使用
					 * 获取列的别名:rsmd.getColumnLabel()——没有起别名时,默认返回列的列名
					 */
					Object columnValue = rs.getObject(i+1);
					String columnLabel = rsmd.getColumnLabel(i+1);
					//通过反射,将该值赋值给order对象的对应属性
					Field field = Order.class.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(order, columnValue);
				}
				return order;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(rs, ps, conn);
		}
		return null;	
		
	}
}

通用的增删改查操作

增删改

package jdbc_1.preparedStatement;

import java.sql.Connection;
import java.sql.PreparedStatement;

import org.junit.Test;

import jdbc_1.myutil.JDBCUtils;

/**
 * 通用的数据库增删改操作
 * @author MCC
 *
 */
public class CUDGeneralTest {
	@Test
	public void testCUD() throws Exception {
//		CUD("delete from customers where id = ?", 3);
//		CUD("update `order` set order_name = ? where order_id = ?", "DD", 2);
		CUD("insert into `order` (order_name, order_date) values (?, ?)", "FF", "1990-2-1");
	}
	
	public void CUD(String sql, Object ...obj) {
		//sql中占位符的个数应该与可变形参的长度相同
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.获取连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译sql语句,获取PreparedStatement对象	
			ps = conn.prepareStatement(sql);

			//3.填充占位符
			for(int i=0; i<obj.length; i++) {
				ps.setObject(i+1, obj[i]);//sql从1开始,obj从0开始
			}
					
			//4.执行
			ps.execute();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//5.关闭资源
		JDBCUtils.closeResource(ps, conn);
	}
}

查询

package jdbc_1.preparedStatement;

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 org.junit.Test;

import jdbc_1.bean.Customer;
import jdbc_1.bean.Order;
import jdbc_1.myutil.JDBCUtils;

/**
 * 使用PreparedStatement实现针对于不同表的通用查询操作
 * @author MCC
 *
 */
public class selectGeneralTest {
	@Test
	/*
	 * 测试查询单个记录
	 */
	public void testGenOneSelect() {
		String sql1 = "select id, name, email from customers where id = ?";
		Customer customer = testGeneralOneSelect(Customer.class, sql1, 12);
		System.out.println(customer);
		/*
		 * 当类的属性名与表的字段名不一致时,需要给表的各个字段起别名,别名为对应的属性名,
		 * rsmd.getColumnName()方法获取的是表的字段名(即原始名),不是别名,
		 * 因此此时需要更改该方法,使用rsmd.getColumnLabel()方法则可以获取字段的别名
		 */
		String sql2 = 
				"select "
				+ "order_id orderId, "
				+ "order_name orderName, "
				+ "order_date orderDate "
				+ "from `order` where order_id = ?";
		Order order = testGeneralOneSelect(Order.class, sql2, 4);
		System.out.println(order);
	}
	/*
	 * 返回表中的一条记录
	 */
	public <T> T testGeneralOneSelect(Class<T> clazz, String sql, Object ...obj) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			//1.建立连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译sql语句
			ps = conn.prepareStatement(sql);
			
			//3.填充占位符
			for(int i=0; i<obj.length; i++) {
				ps.setObject(i+1, obj[i]);
			}
			
			//4.执行sql,获取结果集对象以及结果集元数据对象
			rs = ps.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			if(rs.next()) {//如果有数据,则取出数据
				T t = clazz.getConstructor().newInstance();
				//根据数据的字段数,判断取出次数
				int columnCount = rsmd.getColumnCount();
				for(int i=0; i<columnCount; i++) {
					//取出数值以及列名
					/*
					 * 获取列的列名:rsmd.getColumnName()——不推荐使用
					 * 获取列的别名:rsmd.getColumnLabel()——没有起别名时,默认返回列的列名
					 */
					Object columnValue = rs.getObject(i+1);
					String columnLabel = rsmd.getColumnLabel(i+1);
					//通过反射,将该值赋值给t对象的对应属性
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}
				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(rs, ps, conn);
		}
		return null;	
		
	}
	@Test
	/*
	 * 测试查询多个记录
	 */
	public void testGenMoreSelect() {
		String sql1 = "select id, name, email from customers";
		List<Customer> customerList = testGeneralMoreSelect(Customer.class, sql1);
		customerList.forEach(System.out::println);
		/*
		 * 当类的属性名与表的字段名不一致时,需要给表的各个字段起别名,别名为对应的属性名,
		 * rsmd.getColumnName()方法获取的是表的字段名(即原始名),不是别名,
		 * 因此此时需要更改该方法,使用rsmd.getColumnLabel()方法则可以获取字段的别名
		 */
		String sql2 = 
				"select "
				+ "order_id orderId, "
				+ "order_name orderName, "
				+ "order_date orderDate "
				+ "from `order` where order_id < ?";
		List<Order> orderList = testGeneralMoreSelect(Order.class, sql2, 4);
		orderList.forEach(System.out::println);
//		for(Order order : orderList) {
//			System.out.println(order);
//		}
	}
	/*
	 * 返回表中的多条记录
	 */
	public <T> List<T> testGeneralMoreSelect(Class<T> clazz, String sql, Object ...obj) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			//1.建立连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译sql语句
			ps = conn.prepareStatement(sql);
			
			//3.填充占位符
			for(int i=0; i<obj.length; i++) {
				ps.setObject(i+1, obj[i]);
			}
			
			//4.执行sql,获取结果集对象以及结果集元数据对象
			rs = ps.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			
			//创建集合对象
			List<T> list = new ArrayList<T>();
			
			while(rs.next()) {//如果有数据,则取出数据
				T t = clazz.getConstructor().newInstance();
				//根据数据的字段数,判断取出次数
				int columnCount = rsmd.getColumnCount();
				//给t对象指定属性赋值
				for(int i=0; i<columnCount; i++) {
					//取出数值以及列名
					/*
					 * 获取列的列名:rsmd.getColumnName()——不推荐使用
					 * 获取列的别名:rsmd.getColumnLabel()——没有起别名时,默认返回列的列名
					 */
					Object columnValue = rs.getObject(i+1);
					String columnLabel = rsmd.getColumnLabel(i+1);
					//通过反射,将该值赋值给t对象的对应属性
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}
				//将t对象添加到集合中
				list.add(t);
			}
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(rs, ps, conn);
		}
		return null;	
		
	}
}
	

自定义的工具类

自定义的获取连接和关闭资源的工具类

package jdbc_1.myutil;

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;

/**
 * 操作数据库的工具类
 * @author MCC
 *
 */
public class JDBCUtils {
	/**
	 * 获取数据库连接
	 * @return Connection conn
	 * @throws Exception
	 */
	public static Connection getConnection() throws Exception{
		InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
		Properties prop = new Properties();
		prop.load(in);
		String user = prop.getProperty("user");
		String password = prop.getProperty("password");
		String url = prop.getProperty("url");
		String driverClass = prop.getProperty("driverClass");
		
		//2.加载驱动
		Class.forName(driverClass);
		
		//3.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);
		
		return conn;
	}
	
	/**
	 * 关闭statement和Connection
	 * @param conn
	 * @param s
	 */
	public static void closeResource(Statement s, Connection conn) {
		try {
			if(s != null) {
				s.close();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		try {
			if(conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	//重载
	public static void closeResource(ResultSet rs, Statement s, Connection conn) {
		try {
			if(rs != null) {
				rs.close();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		try {
			if(s != null) {
				s.close();
			}
		} catch(SQLException e2) {
			e2.printStackTrace();
		}
		try {
			if(conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

三、Blob

package jdbc_1.blob;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.junit.Test;

import jdbc_1.bean.Customer;
import jdbc_1.myutil.JDBCUtils;

/**
 * 使用PreparedStatement测试Blob类型的数据		
 * @author MCC
 *
 */
public class BlobTest {
	/*
	 * 1. 向customers表中插入Blob类型数据
	 */
	@Test
	public void testInsetrBlob() throws Exception {
		Connection conn = JDBCUtils.getConnection();
		String sql = "insert into customers (name, email, birth, photo) values (?, ?, ?, ?)";
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setObject(1, "漩涡鸣人");
		ps.setObject(2, "mingren@qq.com");
		ps.setObject(3, "1996-2-19");
		
		FileInputStream fis = new FileInputStream(new File("C:\\Users\\MCC\\Desktop\\20200913142956.jpg"));
		ps.setBlob(4, fis);
		
		ps.execute();
		
		JDBCUtils.closeResource(ps, conn);
		
	}
	
	/*
	 *2. 修改customers表中的Blob数据
	 */
	@Test
	public void testUpdateBlob() throws Exception {
		Connection conn = JDBCUtils.getConnection();
		String sql = "update customers set photo = ? where id = ?";
		PreparedStatement ps = conn.prepareStatement(sql);
		
		FileInputStream fis = new FileInputStream(new File("C:\\Users\\MCC\\Desktop\\20200921230415.jpg"));
		ps.setBlob(1, fis);
		ps.setObject(2, 22);
		
		ps.execute();
		
		JDBCUtils.closeResource(ps, conn);
		
	}
	
	/*
	 * 3. 查询customer表中的Blob数据
	 */
	@Test
	public void testSelectBlob() {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		InputStream bs = null;
		FileOutputStream fos = null;
		try {
			conn = JDBCUtils.getConnection();
			String sql = "select id, name, email, birth, photo from customers where id = ?";
			ps = conn.prepareStatement(sql);

			ps.setObject(1, 22);
			
			rs = ps.executeQuery();
			
			if(rs.next()) {
				//方式1:getXxx(int columnIndex)
//				int id = rs.getInt(1);
//				String name = rs.getString(2);
//				String email = rs.getString(3);
//				Date birth = rs.getDate(4);
				
				//方式2:getXxx(String columnLabel)
				int id = rs.getInt("id");
				String name = rs.getString("name");
				String email = rs.getString("email");
				Date birth = rs.getDate("birth");
				
				Customer cust = new Customer(id, name, email, birth);
				
				System.out.println(cust);
				
				//获取blob数据,并下载到本地
				Blob photo = rs.getBlob("photo");
				bs = photo.getBinaryStream();
				fos = new FileOutputStream(
						new File("C:\\Users\\MCC\\Desktop\\photo.jpg"));
				//读取数据
				byte[] by = new byte[1024];
				int len = 0;
				while((len=bs.read(by))!=-1) {
					//写出
					fos.write(by, 0, len);
				}
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(bs!=null) {
				try {
					bs.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fos!=null) {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			JDBCUtils.closeResource(rs, ps, conn);
		}
		
	}
}

四、批处理

package jdbc_1.batch;

import java.sql.Connection;
import java.sql.PreparedStatement;

import org.junit.Test;

import jdbc_1.myutil.JDBCUtils;

/**
 * 利用PreparedStatement实现批量数据操作
 * 
 * select、update、delete本身就具有批量操作效果
 * 
 * insert需要考虑批量插入问题
 * 
 * 问题:向goods表中插入20000条数据
 * 
 * 方式1:使用Statement
 * 
 * @author MCC
 *
 */
public class BatchTest {
	//方式2:
	@Test
	public void testBatchInsert_2() {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			
			long startTime = System.currentTimeMillis();
			
			conn = JDBCUtils.getConnection();
			String sql = "insert into goods (name) values (?)";
			ps = conn.prepareStatement(sql);
			//填充占位符
			for(int i=0; i<20000; i++) {
				ps.setObject(1, "name_"+(i+1));
				ps.execute();
			}
			long endTime = System.currentTimeMillis();
			long time = endTime-startTime;
			System.out.println(time);//60384ms
		} catch (Exception e) {
			e.printStackTrace();
		} 	
		JDBCUtils.closeResource(ps, conn);	
	}
	
	/*
	 * 方式3:
	 * 改进1:addBatch(), executeBatch(), clearBatch()
	 * 改进2:MySQL默认是关闭批处理功能的,我们需要通过一个参数,让MySQL开启批处理功能。
	* 	  ?rewriteBatchedStatements=true 写在配置文件的url后面
	 */
		@Test
		public void testBatchInsert_3() {
			Connection conn = null;
			PreparedStatement ps = null;
			try {
				
				long startTime = System.currentTimeMillis();
				
				conn = JDBCUtils.getConnection();
				String sql = "insert into goods (name) values (?)";
				ps = conn.prepareStatement(sql);
				//填充占位符
				for(int i=1; i<=1000000; i++) {
					ps.setObject(1, "name_"+(i+1));
					
					//1.“攒”sql
					ps.addBatch();
					
					if(i%500 == 0) {
						//2.执行batch
						ps.executeBatch();
						
						//3.情况batch
						ps.clearBatch();
						
					}
				}
				long endTime = System.currentTimeMillis();
				long time = endTime-startTime;
				System.out.println(time);//15064ms
			} catch (Exception e) {
				e.printStackTrace();
			} 
			JDBCUtils.closeResource(ps, conn);
		}
		
		/*
		 * 方式4:
		 * 在方式3的基础上,设置语句都执行完毕再提交,即1000000条数据都插入之后再提交数据库,
		 * 而不是执行500次就提交一次
		 * 使用Connection 的 setAutoCommit(false)  /  commit()
		 */
			@Test
			public void testBatchInsert_final() {
				Connection conn = null;
				PreparedStatement ps = null;
				try {
					
					long startTime = System.currentTimeMillis();
					
					conn = JDBCUtils.getConnection();
					
					//设置不允许自动提交数据
					conn.setAutoCommit(false);
					
					String sql = "insert into goods (name) values (?)";
					ps = conn.prepareStatement(sql);
					//填充占位符
					for(int i=1; i<=1000000; i++) {
						ps.setObject(1, "name_"+(i+1));
						//1.“攒”sql
						ps.addBatch();
						if(i%500 == 0) {
							//2.执行batch
							ps.executeBatch();
							//3.情况batch
							ps.clearBatch();
						}
					}
					
					//都执行完毕,提交数据
					conn.commit();
					
					long endTime = System.currentTimeMillis();
					long time = endTime-startTime;
					System.out.println(time);//8286ms
				} catch (Exception e) {
					e.printStackTrace();
				} 
				JDBCUtils.closeResource(ps, conn);
			}
			
}

五、练习

练习1:

package jdbc_1.practice;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Scanner;

import org.junit.Test;

import jdbc_1.myutil.JDBCUtils;

/**
 * 从控制台向customers表中插入一条数据,表结构为:
 * id, name, email, birth, photo
 * 
 * @author MCC
 *
 */
public class Practice1Test {
	@Test
	//插入数据
	public void testPractice1() {
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入用户名:");
		String name = scanner.next();
		System.out.println("请输入邮箱:");
		String email = scanner.next();
		System.out.println("请输入生日:");
		String birth = scanner.next();
		
		String sql = "insert into customers (name, email, birth) values (?, ?, ?)";
		int res = CUD(sql, name, email, birth);
		if(res==0) {
			System.out.println("操作失败");
		} else {
			System.out.println("操作成功");
		}
		scanner.close();

	}
	//通用的增删改操作
	public int CUD(String sql, Object ...obj) {
		//sql中占位符的个数应该与可变形参的长度相同
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.获取连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译sql语句,获取PreparedStatement对象	
			ps = conn.prepareStatement(sql);

			//3.填充占位符
			for(int i=0; i<obj.length; i++) {
				ps.setObject(i+1, obj[i]);//sql从1开始,obj从0开始
			}
					
			//4.执行
			/* 方式1:
			 * boolean execute(): 
			 * 如果执行的是查询操作,有结果集,则返回true
			 * 如果执行的是增删改操作,没有结果集,则返回false
			 */
//			ps.execute();
			/* 方式2:
			 * int executeUpdate():
			 * 返回执行增删改操作影响的行数,返回0代表影响行数为0,即增删改失败
			 */
			return ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//5.关闭资源
		JDBCUtils.closeResource(ps, conn);
		return 0;
	}
}

练习2:
在这里插入图片描述
在这里插入图片描述
Class ExamStudent

package jdbc_1.bean;
/**
 * 用来存储从examstudent表中查询到的数据
 * @author MCC
 *
 */
public class ExamStudent {
	private int flowID;//流水号
	private int type;//考试类型
	private String IDCard;//身份证号
	private String examCard;//准考证号
	private String name;//姓名
	private String location;//所在城市
	private int grade;//成绩
	
	public ExamStudent() {
		super();
	}
	
	public ExamStudent(int flowID, int type, String iDCard, String examCard, String name, String location, int grade) {
		super();
		this.flowID = flowID;
		this.type = type;
		IDCard = iDCard;
		this.examCard = examCard;
		this.name = name;
		this.location = location;
		this.grade = grade;
	}
	
	public int getflowID() {
		return flowID;
	}
	
	public void setflowID(int flowID) {
		this.flowID = flowID;
	}
	
	public int getType() {
		return type;
	}
	
	public void setType(int type) {
		this.type = type;
	}
	
	public String getIDCard() {
		return IDCard;
	}
	
	public void setIDCard(String iDCard) {
		IDCard = iDCard;
	}
	
	public String getExamCard() {
		return examCard;
	}
	
	public void setExamCard(String examCard) {
		this.examCard = examCard;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getLocation() {
		return location;
	}
	
	public void setLocation(String location) {
		this.location = location;
	}
	
	public int getGrade() {
		return grade;
	}
	
	public void setGrade(int grade) {
		this.grade = grade;
	}
	
	@Override
	public String toString() {
		return "ExamStudent [flowID=" + flowID + ", type=" + type + ", IDCard=" + IDCard + ", examCard=" + examCard
				+ ", name=" + name + ", location=" + location + ", grade=" + grade + "]";
	}
	
	//显示学生信息
	public void showInfo() {
		System.out.println("=======查询结果========");
		System.out.println("流水号:" + this.flowID + "\n" +
							"四级/六级:" + this.type + "\n" + 
							"身份证号:" + this.IDCard + "\n" + 
							"准考证号:" + this.examCard + "\n" + 
							"姓名:" + this.name + "\n" + 
							"成绩:" + this.grade);
	}
	
}

package jdbc_1.practice;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Scanner;

import org.junit.Test;

import jdbc_1.bean.ExamStudent;
import jdbc_1.myutil.JDBCUtils;

/**
 * 课后练习2
 * @author MCC
 *
 */
public class Practice2Test {
	@Test
	public void testPractice2() {
		System.out.println("请输入考生的详细信息");
		Scanner scanner = new Scanner(System.in);
		System.out.print("四级/六级(4/6):");
		int type = scanner.nextInt();
		System.out.print("身份证号:");
		String idCard = scanner.next();
		System.out.print("准考证号:");
		String examCard = scanner.next();
		System.out.print("姓名:");
		String studentName = scanner.next();
		System.out.print("所在城市:");
		String location = scanner.next();
		System.out.print("成绩:");
		int grade = scanner.nextInt();
		
		String sql = "insert into examstudent "
				+ "(Type, IDCard, ExamCard, StudentName, Location, Grade) "
				+ "values (?, ?, ?, ?, ?, ?)";
		int res = CUD(sql, type, idCard, examCard, studentName, location, grade);
		if(res==0) {
			System.out.println("信息录入失败!");
		} else {
			System.out.println("信息录入成功!");
		}
		scanner.close();
	}
	
	/*
	 * 问题1:向examstudent表中添加数据
	 */
	public int CUD(String sql, Object ...obj) {
		//sql中占位符的个数应该与可变形参的长度相同
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.获取连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译sql语句,获取PreparedStatement对象	
			ps = conn.prepareStatement(sql);

			//3.填充占位符
			for(int i=0; i<obj.length; i++) {
				ps.setObject(i+1, obj[i]);//sql从1开始,obj从0开始
			}
					
			//4.执行
			/* 方式1:
			 * boolean execute(): 
			 * 如果执行的是查询操作,有结果集,则返回true
			 * 如果执行的是增删改操作,没有结果集,则返回false
			 */
//			ps.execute();
			/* 方式2:
			 * int executeUpdate():
			 * 返回执行增删改操作影响的行数,返回0代表影响行数为0,即增删改失败
			 */
			return ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//5.关闭资源
		JDBCUtils.closeResource(ps, conn);
		return 0;
	}
	
	@Test
	public void testPractice2_2() {
		System.out.println("请选择您要输入的类型:\na:准考证号\nb:身份证号");
		Scanner scanner = new Scanner(System.in);
		String selection = scanner.next();
		//避免空指针异常
		if("a".equals(selection)) {
			System.out.println("请输入准考证号:");
			String examCard = scanner.next();
			String sql = "select FlowID flowID,Type type,IDCard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where examCard = ?";
			ExamStudent student = testGeneralOneSelect(ExamStudent.class, sql, examCard);
			if(student != null) {
				student.showInfo();
			}else {
				System.out.println("查无此人,请重新进入程序!");
			}
			
		} else if("b".equals(selection)) {
			System.out.println("请输入身份证号:");
			String IDCard = scanner.next();
			String sql = "select FlowID flowID, Type type, IDCard, ExamCard examCard, StudentName name, Location location, Grade grade from examstudent where IDCard = ?";
			ExamStudent student = testGeneralOneSelect(ExamStudent.class, sql, IDCard);
			if(student != null) {
				student.showInfo();
			}else {
				System.out.println("查无此人,请重新进入程序!");
			}
			
		} else {
			System.out.println("您的输入有误,请重新进入程序!");
		}
		
		scanner.close();
	}
	
	/*
	 * 问题2:根据身份证号或准考证号查询学生的成绩信息
	 */
	public <T> T testGeneralOneSelect(Class<T> clazz, String sql, Object ...obj) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			//1.建立连接
			conn = JDBCUtils.getConnection();
			
			//2.预编译sql语句
			ps = conn.prepareStatement(sql);
			
			//3.填充占位符
			for(int i=0; i<obj.length; i++) {
				ps.setObject(i+1, obj[i]);
			}
			
			//4.执行sql,获取结果集对象以及结果集元数据对象
			rs = ps.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			if(rs.next()) {//如果有数据,则取出数据
				T t = clazz.getConstructor().newInstance();
				//根据数据的字段数,判断取出次数
				int columnCount = rsmd.getColumnCount();
				for(int i=0; i<columnCount; i++) {
					//取出数值以及列名
					/*
					 * 获取列的列名:rsmd.getColumnName()——不推荐使用
					 * 获取列的别名:rsmd.getColumnLabel()——没有起别名时,默认返回列的列名
					 */
					Object columnValue = rs.getObject(i+1);
					String columnLabel = rsmd.getColumnLabel(i+1);
					//通过反射,将该值赋值给t对象的对应属性
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}
				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(rs, ps, conn);
		}
		return null;	
		
	}
	
	/*
	 * 问题3:删除指定考生的信息
	 */
	@Test
	public void testPractice2_3() {
		System.out.println("请输入学生的准考证号:");
		Scanner scanner = new Scanner(System.in);
		String examCard = scanner.next();
		//先查询该考号学生是否存在
		String sql1 = "select  FlowID flowID,Type type,IDCard,ExamCard examCard,StudentName name,Location location,Grade grade from examstudent where examCard = ?";
		ExamStudent student = testGeneralOneSelect(ExamStudent.class, sql1, examCard);
		if(student == null) {
			System.out.println("查无此人,请重新输入!");
		}else {
			String sql2 = "delete from examstudent where ExamCard = ?";
			int res = CUD(sql2, examCard);
			if(res>0) {
				System.out.println("删除成功!");
			}else {
				System.out.println("删除失败!");
			}
		}
		scanner.close();
	}
	
	//改进方法
	@Test
	public void testPractice2_4() {
		System.out.println("请输入学生的准考证号:");
		Scanner scanner = new Scanner(System.in);
		String examCard = scanner.next();
		/*
		 * 不进行查询,直接删除指定准考证号的考生信息,
		 * 如果该生存在,则删除成功,如果不存在也不会报错,受影响行数为0
		 */
		String sql = "delete from examstudent where ExamCard = ?";
		int res = CUD(sql, examCard);
		if(res>0) {
			System.out.println("删除成功!");
		}else {
			System.out.println("查无此人,请重新输入!");
		}
		scanner.close();
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值