目录


Java数据库组织架构

下载驱动包

连接数据库

  连接数据库的三个步骤

  连接数据库的高开销

Statement接口介绍

PreparedStatement类

  使用PreparedStatement进行DML操作

  使用PreparedStatement进行DQL操作

JDBC事务处理

批量SQL操纵

数据库存取文本内容的大对象(CLOB)

数据库存取二进制的大对象(BLOB)

存blob数据的时候,文件过大存不下的解决方法

将数据库连接配置保存到外部properties文件中


Java数据库组织架构

  因为有很多中数据库,比如常见的MySQL、Oracle、SqlServer、Sqlite..... 这些数据库都有自己的特性,如果Java为每一种数据库开发一套API,进行数据库操作,那么将是很头疼的,原因如下:  

  

  1、每一种数据库都有差异,那么就代表每一套API的使用方法可能都不同;

  2、不便于数据库迁移,比如,前期使用MySQL,到后期发现Oracle更加适合项目,于是将数据从MySQL迁移到Oracle中了,因为API不同,所以需要重新修改所有的SQL操作。

  3、除此之外,这么多套API,维护起来也是很麻烦的;

  

  Java采用的方式:

  提供统一API定义,API的实现则由各数据库厂商自己提供(jar包,以驱动的形式),再使用的时候,加载所需要的数据库驱动即可。他的架构图如下:

   

  这样做的好处是显而易见的,可以解决上面的问题,在使用的时候,不用可以关心底层使用什么数据库,只需要关心业务逻辑即可。

下载驱动包

  下载地址:http://static.runoob.com/download/mysql-connector-java-5.1.39-bin.jar

  下载之后将jar包添加到buildpath中即可。

连接数据库

  连接数据库主要有三个步骤

  1、加载数据库驱动类

  2、设置连接数据库的相关信息

  3、连接数据库

package lixin.gan.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException; public class ConnectDB {
public static void main(String[] args) throws ClassNotFoundException, SQLException { // 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver"); // 指定数据库连接信息
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root"; // 连接数据库
Connection connection = DriverManager.getConnection(url, user, password); System.out.println(connection); // com.mysql.jdbc.JDBC4Connection@377dca04 }
}

  

  连接数据库的高开销

  其实我们连接数据库,创建Connection对象,就是创建一个和数据库服务器的Socket连接(传输层,使用TCP),通常应用程序和数据库服务器不再同一台机器上,这就涉及到了网络IO,网络IO的速度并不快。

  下面测试一下建立一次连接所花费的时间:

package lixin.gan.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException; public class TestTimeToConnectDB {
public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root"; long start = System.currentTimeMillis();
DriverManager.getConnection(url, user, password);
long end = System.currentTimeMillis();
System.out.println("连接本地数据库, 花费了 " + (end-start) + " 毫秒");
// 1128毫秒 1136毫秒 1193毫秒 }
}

   从上面的统计结果来看(与测试环境有关),建立连接的耗时的确是挺高的,在大型应用中,这样的开销明显是不能接受的。一般的解决方法是使用连接池。

Statement接口的介绍

  与数据库建立了联系之后,就可以进行数据库操作了,这是需要使用Statement接口。这个Statement接口有两个子类,分别是PreparedStatement和CallableStatement。Statement接口中定义的那些方法,在PreparedStatement和CallcableStatement类中也同样可以使用。

  Statement接口主要有三个常用的方法:

// 可以用来执行所有的SQL语句,执行DML返回false,执行DQL获得结果集则返回true
boolean java.sql.Statement.execute(String sql) // 用来执行DQL语句,比如select,返回查询的结果集
ResultSet java.sql.Statement.executeQuery(String sql) // 用来执行DML语句,比如insert、update、delete,返回受影响的记录数
int java.sql.Statement.executeUpdate(String sql)

  我们一般不使用Statement,而是使用它的实现类PreparedStatement。因为Statement是直接将SQL拼接之后执行,会有SQL注入的风险。而PreparedStatement可以先进行预处理,可以有效地防止SQL注入。

package lixin.gan.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement; public class UseStatement {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password); // 获取Statement对象
Statement statement = connection.createStatement(); String sql = "select * from user";
boolean flag = statement.execute(sql);
System.out.println(flag); // 执行查询操作,返回true sql = "delete from user where uid=1";
flag = statement.execute(sql);
System.out.println(flag); // 执行insert、delete、update操作,返回false }
}

  

PreparedStatement类的使用

  PrepareStatement类是Statement类的子类,可以对SQL进行预处理,并通过参数绑定的方式来防止SQL注入。同样的,PreparedStatement同样有execute()、executeQuery()、executeUpdate()三个方法。

  使用PreparedStatement进行DML操作

package lixin.gan.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException; public class UsePreparedStatementRunDML {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password); // 准备SQL语句,参数使用?进行占位
String sql = "insert into user (username, pwd, birthday) value (?, ?, ?)"; // 进行预处理,获得prepareStatement对象
PreparedStatement prepareStatement = connection.prepareStatement(sql); // 为sql中的占位符绑定值, setXxx(index, value); index从1开始计数
prepareStatement.setString(1, "test");
prepareStatement.setString(2, "98765");
prepareStatement.setDate(3, new java.sql.Date(System.currentTimeMillis()));
// 注意此时导入的是java.sql.Date; 这个类是java.util.Date的子类 // 使用executeUpdate()进行DML操作
int affectedRows = prepareStatement.executeUpdate();
System.out.println(affectedRows); // 1 /**
* 上面是准确知道每一个参数的类型,可以使用setXxx来绑定参数
* 如果不知道准确的参数类型,可以采取偷懒的方式,使用setObject()
*/
prepareStatement.setObject(1, "demo");
prepareStatement.setObject(2, "8888");
prepareStatement.setObject(3, new java.sql.Date(System.currentTimeMillis()));
affectedRows = prepareStatement.executeUpdate();
System.out.println(affectedRows); // 1 // 释放资源
if (prepareStatement != null) {
prepareStatement.close();
} if (connection != null) {
connection.close();
} }
}

  

  使用PreparedStatement对象进行DQL操作

package lixin.gan.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import com.sun.corba.se.spi.orbutil.fsm.Guard.Result; /**
* 使用PreparedStatement进行查询操作
*/
public class UsePreparedStatementRunDQL { public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password); // 准备SQL语句,参数使用?进行占位
String sql = "select uid, username, pwd, birthday from user where uid > ?"; // 进行预处理,获得prepareStatement对象
PreparedStatement prepareStatement = connection.prepareStatement(sql); // 绑定参数
prepareStatement.setInt(1, 3); // 使用executeQuery()执行查询DQL操作,获得的ResultSet对象相当于结果集中的游标
ResultSet resultSet = prepareStatement.executeQuery(); // 循环遍历结果集,打印所有数据
while(resultSet.next()) {
// 可以使用resultSet.getXxx(int num)来获取第num个字段的值,数据类型是Xxx
System.out.println(
resultSet.getInt(1) + "--" +
resultSet.getString(2) + "--" +
resultSet.getString(3) + "--" +
resultSet.getDate(4)
); // 也可以使用resultSet.getXxx(columnName)来获取columnName字段的值,数据类型是Xxx
System.out.println(
resultSet.getInt("uid") + "--" +
resultSet.getString("username") + "--" +
resultSet.getString("pwd") + "--" +
resultSet.getDate("birthday")
);
} // 关闭连接--->先打开的,后关闭
if (resultSet != null) {
resultSet.close();
} if (prepareStatement != null) {
prepareStatement.close();
} if (connection != null) {
connection.close();
} }
}

  

JDBC事务处理

  事务的概念这里就不在累述了,jdbc在进行事务操作的时候,无非就是4个注意点:

  1、执行SQL前,要关闭自动提交

  2、执行任意一个SQL时,如果出现错误要抛出异常,捕获异常后,进行回滚操作

  3、如果所有SQL都执行成功,需要进行提交,将所有操作的结果都持久化到数据库

  4、最后的,也是最重要的,数据库存储引擎一定要是InnoDB,不要使用MyISAM

package lixin.gan.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException; /**
* 测试事务操作
*/
public class TransactionInJDBC {
public static void main(String[] args) { Connection connection = null;
PreparedStatement preparedStatement = null; try {
Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password); connection.setAutoCommit(false); // 关闭自动提交 String sql = ""; // 进行操作 1
sql = "update user set username='God' where uid=?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 4);
preparedStatement.executeUpdate(); // 在进行下一次预处理SQL之前,要先释放一下上一次额预处理
preparedStatement.close(); // 进行操作 2 , 字段名username故意写错为usernema,所以数据库操作会失败,并抛出异常,触发回滚操作
sql = "insert into user (usernema, pwd) values (?, ?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "qwe");
preparedStatement.setString(2, "123456");
preparedStatement.executeUpdate(); // 如果到这里都没有抛出异常,那么表示所有SQL执行成功,于是可以提交操作
connection.commit(); } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace(); // 检测到SQLException,并且连接数据库成功,所以,肯定是执行SQL出错了,于是进行回滚操作
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
} finally { // 释放资源
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}

 

批量SQL操作

  有时候,我们需要有很多SQL需要执行,我们可以每次执行1条,这样的效率并不怎么高,Java提供了批量执行SQL,首先需要将要执行的SQL添加到statement对象保存sql的列表中,之后调用executeBatch()执行保存的所有SQL。

  批量执行SQL需要有以下几个注意点:

  1、要关闭自动提交(采用事务处理)

  2、对于将要执行的SQL,调用addBatch()保存

  3、调用executeBatch()执行批量SQL

  4、提交commit

package lixin.gan.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random; /**
* 使用批量的数据库操作,并测试与单一操作的效率
*/
public class UseAddBatch { private static String url = "jdbc:mysql://localhost:3306/test";
private static String user = "root";
private static String password = "root"; private static Connection connection = null;
private static Statement statement = null; /**
* 关闭连接,释放资源
*/
private static void freeResource(Connection connection, Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 批量执行SQL
*/
public static void runBatchSqlOneTime() {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url, user, password); // 批量执行SQL之前,需要关闭自动提交,防止中途有SQL执行失败。
connection.setAutoCommit(false); // 批量执行SQL的时候,一般不会使用预处理PreparedStatement,一般是使用Statement
statement = connection.createStatement(); for (int i = 0; i < 1000; i++) {
statement.addBatch("insert into person (name, age) value ('test" + i + "', " + i%10 + ")");
}
// addBatch(sql) 会将传入的sql保存到statement对象的sql列表中 // 执行批量statement对象sql列表中的所有sql
statement.executeBatch(); connection.commit(); } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
// 中途出现错误
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
} finally {
freeResource(connection, statement);
}
} /**
* 一次执行一次SQL
*/
public static void runSingleSqlOneTime() {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url, user, password); statement = connection.createStatement(); for (int i = 0; i < 1000; i++) {
statement.executeUpdate("insert into person (name, age) value ('test" + i + "', " + i%10 + ")");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
freeResource(connection, statement);
}
} /**
* 一次执行一次SQL,使用事务
*/
public static void runSingleSqlOneTimeUseTransaction() {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(url, user, password);
connection.setAutoCommit(false);
statement = connection.createStatement();
for (int i = 0; i < 1000; i++) {
statement.executeUpdate("insert into person (name, age) value ('test" + i + "', " + i%10 + ")");
}
connection.commit();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
// 中途出现错误
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
} finally {
freeResource(connection, statement);
}
} public static void main(String[] args) {
long start = System.currentTimeMillis();
runBatchSqlOneTime();
long end = System.currentTimeMillis();
System.out.println("批量执行1千条SQL, 耗费了 " + (end-start) + " 毫秒"); start = System.currentTimeMillis();
runSingleSqlOneTime();
end = System.currentTimeMillis();
System.out.println("每次执行1条SQL,不使用事务,执行1千条SQL, 耗费了 " + (end-start) + " 毫秒"); start = System.currentTimeMillis();
runSingleSqlOneTimeUseTransaction();
end = System.currentTimeMillis();
System.out.println("每次执行1条SQL,使用事务,执行1千条SQl, 耗费了 " + (end-start) + " 毫秒"); /**统计结果(执行1千条SQL)
批处理 不使用事务,每次执行一条sql 使用事务,一次执行一条sql
2092 毫秒 39613 毫秒 418 毫秒
1887 毫秒 39066 毫秒 344 毫秒
1951 毫秒 32131 毫秒 339 毫秒
*/
}
}

  从上面的统计结果来看,批处理   只是比   不适用事务,每次执行一条的效率   高20倍左右,但是,如果使用事务,一次执行一条,这样的效率也挺高的,比批处理的效率高5倍。可以根据具体的使用场景来选择策略

  

数据库存取文本内容的大对象(CLOB)

  CLOB用来存储大量的文本内容,在数据库中的数据类型就是text相关的那几个:

  1、tinytext  最大长度是255字节的文本内容(按照utf8编码,约86个汉字)

  2、text 最大长度是65535(64K)字节的文本内容

  3、mediumtext 最大长度是16777215(16M)字节的文本内容

  4、longtext 最大长度是4G字节的文本内容

  注意

    1、上面的各种数据类型的单位都是字节

    2、varchar数据类型的最大长度不能超过65535

    3、Java操作CLOB是以字符流的形式(reader)

package lixin.gan.test;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; public class UseClob { private static String url = "jdbc:mysql://localhost:3306/test";
private static String user = "root";
private static String password = "root"; private static Connection connection = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null; private static Reader reader = null;
private static BufferedReader bufferedReader = null; /**
* 存储大文本对象数据到数据库中
*/
public static void storeClobData() {
try {
Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(url, user, password); String sql = "insert into person (name, introduction) values (?, ?)";
preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, "test"); // 对于大文本对象Clob,绑定参数使用setClob或者使用setObject()
//preparedStatement.setClob(parameterIndex, reader);
Reader reader = new InputStreamReader(new FileInputStream("data.txt"));
preparedStatement.setClob(2, reader); preparedStatement.executeUpdate(); } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
freeResource(connection, preparedStatement);
}
} /**
* 从数据库中取出大文本对象
*/
public static void fetchClobData() {
try {
Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(url, user, password); String sql = "select name, introduction from person where id=?";
preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1, 7); resultSet = preparedStatement.executeQuery(); resultSet.next();
String name = resultSet.getString("name");
Clob introduction = resultSet.getClob("introduction"); // 获取字符流
reader = introduction.getCharacterStream();
bufferedReader = new BufferedReader(reader);
String line = "";
while((line = bufferedReader.readLine()) != null) {
System.out.println(line);
} } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
freeResource(reader, bufferedReader);
freeResource(connection, preparedStatement, resultSet);
}
} /**
* 主入口执行代码
* @param args
*/
public static void main(String[] args) {
storeClobData();
fetchClobData();
} /**
* 释放资源
* @param connection
* @param preparedStatement
*/
private static void freeResource(Connection connection, PreparedStatement preparedStatement) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 释放资源
* @param connection
* @param preparedStatement
* @param resultSet
*/
private static void freeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 释放资源
* @param reader
* @param bufferedReader
*/
private static void freeResource(Reader reader, BufferedReader bufferedReader) {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
} if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

  

数据库存取二进制的大对象(BLOB)

  BLOB是指大量的二进制数据(Binary Large Object),与BLOB对应的数据类型如下:

  1、tinyblob 最大长度是255字节的二进制数据

  2、blob 最大长度是65535(64K)字节的文本内容

  3、mediumblob  最大长度是16777215(16M)字节的文本内容

  4、longblob 最大长度是4G字节的文本内容

  注意

    1、上面的各种数据类型的单位都是字节

    3、Java操作BLOB是以字节流的形式(stream)

package lixin.gan.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; /**
* 存取二进制数据
*/
public class UseBlob { private static String url = "jdbc:mysql://localhost:3306/test";
private static String user = "root";
private static String password = "root"; private static Connection connection = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null; private static InputStream inputStream = null;
private static BufferedInputStream bufferedInputStream = null;
private static BufferedOutputStream bufferedOutputStream = null; /**
* 主入口执行代码
* @param args
*/
public static void main(String[] args) {
storeBlobData();
fetchBlobData();
} public static void storeBlobData() {
try {
Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(url, user, password); String sql = "insert into person (name, image) values (?, ?)";
preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, "test"); // 对于大文本对象Clob,绑定参数使用setClob或者使用setObject()
// preparedStatement.setBlob(parameterIndex, inputStream);
preparedStatement.setBlob(2, new FileInputStream("pic.png")); preparedStatement.executeUpdate(); } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
freeResource(connection, preparedStatement);
}
} public static void fetchBlobData() {
try {
Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(url, user, password); String sql = "select name, image from person where id=?";
preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1, 11); resultSet = preparedStatement.executeQuery(); resultSet.next();
String name = resultSet.getString("name");
// 读取BLOB数据
Blob data = resultSet.getBlob("image"); // 获取字节流,将数据另存为一个文件
inputStream = data.getBinaryStream();
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("newPic.png"));
byte[] buf = new byte[1024];
int length = -1;
while((length = inputStream.read(buf)) != -1) {
bufferedOutputStream.write(buf, 0, length);
}
bufferedOutputStream.flush(); } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
freeResource(inputStream, bufferedOutputStream);
freeResource(connection, preparedStatement, resultSet);
}
} /**
* 释放资源
* @param connection
* @param preparedStatement
*/
private static void freeResource(Connection connection, PreparedStatement preparedStatement) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 释放资源
* @param connection
* @param preparedStatement
* @param resultSet
*/
private static void freeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 释放资源
* @param reader
* @param bufferedReader
*/
private static void freeResource(InputStream inputStream, BufferedOutputStream bufferedOutputStream) {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
} if (bufferedOutputStream != null) {
try {
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

  

存blob数据的时候,文件过大存不下的解决方法

  上面的代码,如果将过大的文件放进数据库,就会出现下面的错误:

Packet for query is too large (1245018 > 1048576).
You can change this value on the server by settin

  上面的错误信息已经说得很明确了,问题在于MySQL对于每一个Packet的数据量的大小默认是不能超过1M的,要想解决这个问题,window下可以修改mysql的配置文件my.ini,在[mysqld]下面查找“max_allowed_packet”这一项,修改他的值即可;如果没有这一项,可以在最后加上这一项,比如要设置为16M,则增加“max_allowed_packet=16M” 即可

将数据库连接配置保存到外部properties文件中

  数据库的连接配置需要设置driver、url、username、password,这些值都不应该在代码中写死,因为:

  1、开发时使用的数据库和线上环境的数据库不相同(连接信息)。

  2、一旦配置发生修改,就需要修改代码,很不方便,另外定位代码是个问题。

  现在通常的做法是将配置信息都保存到一个文件中,程序在连接数据库的时候,读取该配置文件中的配置项即可。部署项目的时候,并不需要修改源码,只需要上传线上环境的配置文件即可。

  下面是一个示例:

  在src目录下,创建一个database.properties文件,内容如下:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root

  连接数据库时,可以这么做,但是不推荐:

package cn.ganlixin.test;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties; public class Test {
public static void main(String[] args) throws Exception { Properties properties = new Properties();
properties.load(new FileInputStream("src/database.properties")); String driver = properties.getProperty("jdbc.driver");
String url = properties.getProperty("jdbc.url");
String username = properties.getProperty("jdbc.username");
String password = properties.getProperty("jdbc.password"); Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password); // ........
}
}

  为什么说上面的做法不推荐呢?因为上面的做法中,是从读取的src目录下的database.properties文件,但是,我们在做项目的时候,项目编译后,执行的是是bin目录下字节码(*.class),而不是src下的源码(*.java),而我们写在src目录下的其他文件,都会被拷贝到bin目录下。所以,正确的方式,我们应该读取bin目录下的配置文件。

package cn.ganlixin.test;

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties; public class Test {
public static void main(String[] args) throws Exception { InputStream inputStream = null;
// 使用类加载器加载的配置文件
inputStream = Test.class.getClassLoader().getResourceAsStream("database.properties"); Properties properties = new Properties();
properties.load(inputStream); String driver = properties.getProperty("jdbc.driver");
String url = properties.getProperty("jdbc.url");
String username = properties.getProperty("jdbc.username");
String password = properties.getProperty("jdbc.password"); Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password); // ........
}
}

  

Java 数据库操作的更多相关文章

  1. 复习java数据库操作的总结

    以前学习java数据库操作,学得那叫糊里糊涂,各种JDBC常用的类和接口根本是傻傻分不清啥是干嘛的.只是套着用用吧. 不过这次好歹清楚些了,呜呜,学习有阶段性,多次重复才有好效果,多么痛的领悟. 工程 ...

  2. Java数据库操作

    一.JDBC 1.JDBC Java数据库连接,用于Java程序中实现数据库操作功能,java.sql包中提供了执行SQL语句,访问各种数据库的方法,并为各种不同的数据库提供统一的操作接口及类. 2. ...

  3. Java数据库操作(MySQL与SQLserver)

    在java编程开发中,数据库的开发是重头戏. MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品: SQL Server是由Microsoft开发 ...

  4. Java数据库操作(JDBC)

    JDBC Java数据库连接(Java DataBase Connectivity,JDBC)用于在Java程序中实现数据库操作功能,它提供了执行SQL语句.访问各种数据库的方法,并为各种不同的数据库 ...

  5. Java数据库操作类演示

    只在mysql上测试过,不知道算不算好使​1. [代码][Java]代码     package org.load.demo; import java.io.IOException;import ja ...

  6. Java 学习笔记(16)——Java数据库操作

    数据库操作是程序设计中十分重要的一个部分,Java内置JDBC来操作数据库 JDBC使用 JDBC--Java Database connecting Java数据库连接:本质上JDBC定义了操作数据 ...

  7. Java数据库操作学习

    JDBC是java和数据库的连接,是一种规范,提供java程序与数据库的连接接口,使用户不用在意具体的数据库.JDBC类型:类型1-JDBC-ODBC桥类型2-本地API驱动类型3-网络协议驱动类型4 ...

  8. java数据库操作:JDBC的操作

    1,JDBC注意操作类及接口: 数据库操作过程: 1)打开数据库服务 2)连接数据库:一般都要输入用户名,密码, 3)操作数据库:创建表:查询表,更新,记录. 4)关闭数据库. 1,DriverMan ...

  9. Java数据库操作大全

    1.提取单条记录 //import java.sql.*; Connection con=null; Statement stmt=null; ResultSet %%6=null; try { Cl ...

随机推荐

  1. Docker+Nextcloud快速部署个人网盘

    各位大佬好,,,萌新顾北清又回来更新了,今天要快速部署一个人网盘. 有多快呢,,,5分钟吧,因为我们使用Docker部署. Docker基础可以看看我之前的博文.(点这里点这里) 那么,,,开始吧. ...

  2. February 12th, 2018 Week 7th Monday

    One man's fault is another man's lesson. 前车之覆,后车之鉴. We make mistakes every day, large or small, fail ...

  3. IntelliJ IDEA 创建Spring+SpringMVC+hibernate+maven项目

    第一步: 新建maven管理的web项目, 具体步骤参考:http://www.cnblogs.com/gczmn/p/8693734.html 第二步: 创建项目结构, 完整项目结构如下: 第三步: ...

  4. git使用命令行拉取远程代码仓库中的分支至本地

    1.本地创建文件夹用于存放拉取的代码 2.执行git init初始化文件夹 3.与远程代码仓库建立连接 git remote add origin git@github.com.wuylin/noth ...

  5. 【PS技巧】如何拼图

    1.材料准备 根据对图片的内容表达,粗略的“计划”,每张图片摆放位置及尺寸.C与D等高,C/D与B叠高后与A等高.C与D叠宽后与B等宽. 2.记录每张图片原始大小 (1)双击工作区,打开待拼接图片 ( ...

  6. 【NOI2018模拟】Yja

    [NOI2018模拟]Yja Description 在平面上找\(n\)个点,要求这 \(n\)个点离原点的距离分别为 \(r1,r2,...,rn\) .最大化这\(n\) 个点构成的凸包面积,凸 ...

  7. centos 7.2 64位安装redis

    1.下载redis 可以在新建  /usr/local/redis 文件夹 $ wget http://download.redis.io/releases/redis-4.0.9.tar.gz $ ...

  8. Python requests模块解析XML

    检查QQ是否在线(api感觉不准) import requests from xml.etree import ElementTree qq_str = input('please input the ...

  9. python subprocess.Popen 控制台输出 实时监控百度网ping值

    import subprocess file_out = subprocess.Popen('ping www.baidu.com', shell=True, stdout=subprocess.PI ...

  10. 【转】解决在Android设备播放音频与其他应用重音的问题,并监听耳机的控制按钮

    概述 在安卓开发中免不了需要播放一点音乐了,音频了.但是这时候有别的应用正在播放,这时候就会出现重音的现象,完全影响用户体验,我们的项目就遇上了这样的尴尬,然后查找了一些文档,记录一下: 管理音频焦点 ...