JDBC核心技术(一)

技术体系

一、JDBC概述

1.数据的持久化

持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。大多数情况下,特别是企业级应用,数据
●持久化意味着将内存中的数据保存到硬盘上加以”固化”,而持久化的实现过程大多通过各种关系数据库来完成。
●持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中。

2.Java中的数据存储技术

●在Java中,数据库存取技术可分为如下几类:

➢JDBC直接访问数据库
➢JDO (Java Data Object )技术
➢第三方O/R工具,如Hibernate, Mybatis等

●JDBC是java访问数据库的基石, JDO、Hibernate、 MyBatis等只是 更好的封装了JDBC。

3.JDBC介绍

●JDBC(Java Database Connectivity)是一个独立于特定数据库 管理系统、通用的SQL数据库存取和操作的公共接口(一组API) , 定义了用来访问数据库的标准Java类库,( java.sql.javax.sql )使用这些类库可以以一种标准的方法、方便地访问数据库资源。
●JDBC为访问不同的数据库提供了一种统一的途径 ,为开发者屏蔽了一些细节问题。
●JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

4.JDBC体系结构

JDBC接口( API)包括两个层次:

面向应用的API : Java API ,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
面向数据库的API : Java Driver API ,供开发商开发数据库驱动程序用。

JDBC是sun公司提供一套用于数据库操作的接口, java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。---面向接口编程

5.JDBC程序编写步骤

二、获取数据库连接

package com.xudong.connection;

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

import org.junit.Test;

public class ConnectionTest2 {
	// 方式一:
	@Test
	public void testConnectionTest_1() throws SQLException {
		// 获取Driver的实现类对象
		Driver driver = new com.mysql.jdbc.Driver();

		String url = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8";
		Properties info = new Properties();
		info.setProperty("user", "root");
		info.setProperty("password", "123456");

		Connection conn = driver.connect(url, info);

		System.out.println(conn);
	}

	// 方式二:对方式一的迭代,在如下程序中不出现第三方安装API,使程序具有更好的移植性
	@Test
	public void testConnectionTest_2() throws Exception {
		// 通过 反射 获取Driver实现类对象
		Class<?> clazz = Class.forName("com.mysql.jdbc.Driver");
		Driver driver = (Driver) clazz.newInstance();

		// 提供要连接的数据库
		String url = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8";

		// 提供连接需要的用户名和密码
		Properties info = new Properties();
		info.setProperty("user", "root");
		info.setProperty("password", "123456");

		// 获取连接
		Connection conn = driver.connect(url, info);
		System.out.println(conn);
	}

	// 方式三:使用DriverManager替换Driver
	@Test
	public void testConnectionTest_3() throws Exception {
		// 1.通过 反射 获取Driver实现类对象
		Class<?> clazz = Class.forName("com.mysql.jdbc.Driver");
		Driver driver = (Driver) clazz.newInstance();

		// 2.提供另外三个连接的基本信息
		String url = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8";
		String user = "root";
		String password = "123456";

		// 注册驱动
		DriverManager.registerDriver(driver);
		// 获取连接
		Connection conn = DriverManager.getConnection(url, user, password);
		System.out.println(conn);
	}

	// 方式四:
	@Test
	public void testConnectionTest_4() throws Exception {
		// 1.提供另外三个连接的基本信息
		String url = "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8";
		String user = "root";
		String password = "123456";

		// 2.加载Driver
		Class.forName("com.mysql.jdbc.Driver");

		// 3.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);
		System.out.println(conn);
	}
	
	//方式五:通过读取配置文件的方式获取连接。部署服务器时,若要修改可避免程序重新打包。
	@Test
	public void testConnectionTest() throws Exception{
		//1.读取配置文件中4个基本信息
		InputStream is = ConnectionTest2.class.getClassLoader().getResourceAsStream("jdbc.properties");
		Properties pros = new Properties();
		pros.load(is);
		
		String url = pros.getProperty("url");
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");
		String driverClass = pros.getProperty("driverClass");
		
		//2.加载驱动
		Class.forName(driverClass);
		
		//3.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);
		System.out.println(conn);
	}
}

三、使用PreparedStatement实现CRUD操作

1.操作和访问数据库

●数据库连接被用于向数据库服务器发送命令和SQL语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。
●在java.sql包中有3个接口分别定义了对数据库的调用的不同方式:

Statement:用于执行静态SQL语句并返回它所生成结果的对象。
PreparedStatement:SQL语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。➢CallableStatement:用于执行SQL存储过程

使用Statement操作数据表存在弊端:

➢问题一:存在拼串操作,繁琐
➢问题二:存在SQL注入问题
SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令(如: SELECT user, password FROM user_table WHERE user='a' OR 1 = 'AND password= 'OR '1'='1') , 从而利用系统的SQL引擎完成恶意行为的做法。

PreparedStatement的使用

增删改

package com.xudong.perparedstatement;

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

import org.junit.Test;

import com.xudong.connection.ConnectionTest2;

public class PreparedStatementCRUDTest {
	@Test
	public void testInsert() {
		// 3.获取连接
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			// 1.读取配置文件中4个基本信息
			InputStream is = ConnectionTest2.class.getClassLoader().getResourceAsStream("jdbc.properties");
			Properties pros = new Properties();
			pros.load(is);

			String url = pros.getProperty("url");
			String user = pros.getProperty("user");
			String password = pros.getProperty("password");
			String driverClass = pros.getProperty("driverClass");

			// 2.加载驱动
			Class.forName(driverClass);

			conn = DriverManager.getConnection(url, user, password);

			// 4.预编译SQL语句,返回prepareStatement实例
			String sql = "INSERT INTO customers(id,nam,email,birth) VALUES(?,?,?,?)";// 占位符
			ps = conn.prepareStatement(sql);

			// 5.填充占位符
			ps.setString(1, "11");
			ps.setString(2, "曹洪");
			ps.setString(3, "caohong@qq.com");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			java.util.Date date = sdf.parse("2000-01-11");
			ps.setDate(4, new java.sql.Date(date.getTime()));

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

}


查询

package com.xudong.perparedstatement;

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 java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import com.xudong.bean.Customer;
import com.xudong.util.JDBCUtils;

public class CustomerForQuery {
	/*@Test
	public void testQuery(){
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet resultSet = null;
		try {
			conn = JDBCUtils.getConnection();
			String sql = "select nam,email,birth from customers where id = ?";
			ps = conn.prepareStatement(sql);
			ps.setObject(1, 5);
			
			//执行并返回结果集
			resultSet = ps.executeQuery();
			//处理结果集
			if(resultSet.next()){
				
				String name = resultSet.getString(1);
				String email = resultSet.getString(2);
				Date birth = resultSet.getDate(3);
				
				Customer customer = new Customer(name, email, birth);
				System.out.println(customer);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			//关闭资源
			JDBCUtils.closeResource(conn, ps, resultSet);
		}
		
	}
	*/
	public <T> List<T> queryForCustomers(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 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 columvalue = rs.getObject(i + 1);
					//获取每个列的列名
					//String columnName = rsmd.getColumnName(i + 1);
					//获取每个列的别名
					String columnLabel = rsmd.getColumnLabel(i + 1);
					//给cust对象指定columnName属性,赋值columnLabel
					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;
	}
	
	@Test
	public void testQueryForCustomers(){
		String sql = "select name,email,birth from customers where id > ?";
		List<Customer> list = queryForCustomers(Customer.class,sql, 6);
		list.forEach(System.out::println);
	}
}

javabean

package com.xudong.bean;

import java.sql.Date;

/**
 * ORM编程思想(object relational mapping) 一个数据表对应一个java类 表中的一条记录对应java类的一个对象
 * 表中的一个字段对应java类的一个属性
 */
public class Customer {

	private String name;
	private String email;
	private Date birth;

	public Customer() {
		super();
	}

	public Customer( String name, String email, Date birth) {
		super();

		this.name = name;
		this.email = email;
		this.birth = birth;
	}


	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 [ name=" + name + ", email=" + email + ", birth=" + birth + "]";
	}

}

工具

package com.xudong.util;

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;

//操作数据库的工具类
public class JDBCUtils {
	// 获取数据库的连接
	public static Connection getConnection() throws Exception {
		// 1.读取配置文件中4个基本信息
		InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
		Properties pros = new Properties();
		pros.load(is);

		String url = pros.getProperty("url");
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");
		String driverClass = pros.getProperty("driverClass");

		// 2.加载驱动
		Class.forName(driverClass);

		Connection conn = DriverManager.getConnection(url, user, password);

		return conn;
	}

	// 关闭数据库连接
	public static void closeResource(Connection conn, Statement ps) {
		// 资源关闭
		try {
			if (ps != null)
				ps.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if (conn != null)
				conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	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();
		}
	}
}

PreparedStatement的好处:

书写sql更方便、解决了sql注入问题、可以操作Blob数据,可实现更高效的批量操作

四、操作BLOB类型字段

1.MySQL BLOB类型

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

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

批量插入

修改url:
url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&rewriteBatchedStatements=true

package com.xudong.perparedstatement;

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

import org.junit.Test;

import com.xudong.util.JDBCUtils;

public class InsertTest {
	@Test
	public void testInsert(){
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			
			long start = 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);
				ps.addBatch();//攒sql
				if(i % 500 == 0){
					ps.executeBatch();//执行
					ps.clearBatch();//清空
				}
			}
			conn.commit();
			
			long end = System.currentTimeMillis();
			
			System.out.println("花费时间:" + (end - start));
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			JDBCUtils.closeResource(conn, ps);
		}
	
	}
}
posted @ 2020-08-13 11:41  旭东东  阅读(438)  评论(0编辑  收藏  举报