序
最近事情多,JavaWeb耽误了很久,看到后面就会把前面给忘了。我是跟着视频学习的,视频讲得很全,但是有令人崩溃的地方,那就是把内容讲得比较全,而实际项目用到的内容却仅仅是一小部分。而自己是个小白,自然会在一些不那么重要的地方花费太多的尽力,对此深恶痛绝。想来就需要进行对自己学习的东西进行一些总结,以防止我遗忘!
1、JDBC的基础理解
JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API)。即意味着学好那几个接口的实现就行! 使用这套API可以实现对具体数据库的操作(获取连接、关闭连接、DML、DDL、DCL)
2、环境介绍
- 在数据库中有工程对应的库,并且创建了表
- 在Java工程中的 lib 中导入 jdbc 的jar包
3、详细步骤
3.1、创建数据库配置文件
创建好 jdbc.properties 配置文件,并放在resource文件夹中
user=root
password=root
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
driverClass=com.mysql.jdbc.Driver
另外,常见的数据库URL地址的写法:
- Oracle:jdbc:oracle:thin:@localhost:1521:数据库名
- SqlServer:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=数据库名
- MySql:jdbc:mysql://localhost:3306/数据库名
3.2、读取数据库配置文件信息
InputStream inputStream = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
prop.load(inputStream);
String url = prop.getProperty("url");
String user = prop.getProperty("user");
String password = prop.getProperty("password");
String driverClass = prop.getProperty("driverClass");
3.3、加载驱动与获取连接
//加载驱动
Class.forName(driverClass);
//获取连接
Connection connection = DriverManager.getConnection(url, user, password);
完整的获取连接方法:
public void testConnection5() throws Exception{
//1.读取配置文件中的基本信息,通过类加载器getClassLoader
InputStream inputStream = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
prop.load(inputStream);
String url = prop.getProperty("url");
String user = prop.getProperty("user");
String password = prop.getProperty("password");
String driverClass = prop.getProperty("driverClass");
//加载驱动
Class.forName(driverClass);
//获取连接
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
3.4 执行SQL语句,实现数据库CRUD操作
事前准备
在util文件夹中创建JDBCUtils类:
/**
* 操作数据库的工具类
*/
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 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 connection = DriverManager.getConnection(url, user, password);
return connection;
}
/**
* 关闭连接和statement的操作
* @param connection
* @param ps
*/
public static void closeResource(Connection connection, Statement ps) {
try {
if (ps != null) {
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭资源的操作,用到了方法的重载
* @param connection
* @param ps
* @param rs
*/
public static void closeResource(Connection connection, Statement ps,ResultSet rs){
try {
if (ps != null) {
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
3.4.1 Statement不推荐
一般不直接用这个类,主要两个弊端:
- 拼写sql语句涉及字符串的拼接,很麻烦。
- sql注入问题,极度危险。
3.4.2 PreparedSatement推荐使用
PreparedSatement 是 statement的子接口。可以解决Statement的sql注入问题和拼串问题。这一部分没啥细说的,就是一些模板。
- 通用的增删改操作
public void update(String sql,Object ...args){//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 < args.length;i++){
ps.setObject(i + 1, args[i]);//小心参数声明错误!!
}
//4.执行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
}finally{
//5.资源的关闭
JDBCUtils.closeResource(conn, ps);
}
}
- 通用查询操作
/**
*
* @Description 针对于不同的表的通用的查询操作,返回表中的一条记录
* @author shkstart
* @date 上午11:42:23
* @param clazz
* @param sql
* @param args
* @return
*/
public <T> T getInstance(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]); //这里有一个细节那就是从1开始的!
}
rs = ps.executeQuery();
// 获取结果集的元数据 :ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
if (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);
// 给t对象指定的columnName属性,赋值为columValue:通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
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()) {
T t = clazz.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.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}
3.5 操作Blob类型的变量
概括来说也就是写入操作和读取操作。
写入操作的方法:setBlob(InputStream is);
读取操作的方法: Blob blob = getBlob(int index); InputStream is = blob.getBinaryStream();
具体的方法:
//insert
//向数据表customers中插入Blob类型的字段
@Test
public void testInsert() 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, "yuan@qq.com");
ps.setObject(3,"1992-09-08");
FileInputStream is = new FileInputStream(new File("girl.jpg"));
ps.setBlob(4, is);
ps.execute();
JDBCUtils.closeResource(conn, ps);
}
//查询数据表customers中Blob类型的字段
@Test
public void testQuery(){
Connection conn = null;
PreparedStatement ps = null;
InputStream is = null;
FileOutputStream fos = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select id,name,email,birth,photo from customers where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 21);
rs = ps.executeQuery();
if(rs.next()){
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);
//将Blob类型的字段下载下来,以文件的方式保存在本地
Blob photo = rs.getBlob("photo");
is = photo.getBinaryStream();
fos = new FileOutputStream("zhangyuhao.jpg");
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer, 0, len);
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
JDBCUtils.closeResource(conn, ps, rs);
}
}
3.6 高效的批量插入
- 设置不允许自动提交数据
- .addBatch 先"攒",再一批批执行
@Test
public void testInsert3() {
Connection conn = null;
PreparedStatement ps = null;
try {
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."攒"sql
ps.addBatch();
if(i % 500 == 0){
//2.执行batch
ps.executeBatch();
//3.清空batch
ps.clearBatch();
}
}
//提交数据
conn.commit();
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, ps);
}
}
需要注意的点: mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。?rewriteBatchedStatements=true 写在配置文件的url后面