技术体系
一、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, "[email protected]");
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 List queryForCustomers(Class 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 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 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);
}
}
}