标签:
SUN公司为了简化。统一对数据库的操作,定义一套Java操作数据库的规范,称之为JDBC。
JDBC(Java DataBase Connectivity)Java数据库连接,主要有接口组成。
组成JDBC的2个包:
开发JDBC应用需要以上2个包支持外,还需要导入相应的JDBC的数据库实现,即数据库驱动。
DriverManager.registerDriver(Driver driver); //不建议采用这种方式
Class.forName("com.mysql.jdbc.Driver"); //建议采用这种方式
Connection coon = DriverManager.getConnection(url, user, pwd);
Statement st = conn.createStatement();
PreparedStatement pst = conN.prepareStatement(SQL);
ResultSet rs = st.excuteQuery(sql)
resultset rs = pst.executequery();
断开与数据库的连接,并释放相关资源
// --------------MySql脚本--------------------------
create database jdbc character set utf8 collate utf8_general_ci;
use jdbc;
create table user (
id int primary key auto_increment,
name varchar(40),
password varchar(40),
email varchar(60),
birthday date
)character set utf8 collate utf8_general_ci;
insert into user(name, password, email, birthday) values (‘admin‘, ‘admin‘, ‘admin@126.com‘, ‘1990-02-01‘);
insert into user(name, password, email, birthday) values (‘hsx‘, ‘hsx‘, ‘hsx@126.com‘, ‘1990-10-11‘);
insert into user(name, password, email, birthday) values (‘hhh‘, ‘hhh‘, ‘hhh@126.com‘, ‘1990-12-12‘);
注:在mysql中存在着各种utf8编码格式,如下表:
1)utf8_bin -- 将字符串中的每一个字符用二进制数据存储,区分大小写。
2)utf8_general_ci -- 不区分大小写,ci为case insensitive的缩写,即大小写不敏感。
3)utf8_general_cs -- 区分大小写,cs为case sensitive的缩写,即大小写敏感。
// --------------JDBC的Java程序-------------------------
package com.hsx;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JDBC {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1、 加载驱动
/**
* 在实际开发中不推荐使用registerDriver()方法加载驱动,
* 原因1:若采用这种方式,驱动程序会注册两次,即在内存中会有两个Driver对象;
* 原因2:若脱离了mysql的api,脱离了musql的jar包,程序将无法编译,将来程序切换底层数据库会非常麻烦。
* 推荐使用方式:Class.forName("com.mysql.jdbc.Driver");
*/
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2、 连接数据库
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "123456");
//3、 创建用于向数据库发送的SQL的Statement对象
statement = connection.createStatement();
String sql = "select id, name, password, email, birthday from user";
//4、从代表结果集的ResultSet中取数据
resultSet = statement.executeQuery(sql);
// 打印
while (resultSet.next()) {
System.out.print(resultSet.getObject("id"));
System.out.print("\t" + resultSet.getObject("name"));
System.out.print("\t" + resultSet.getObject("password"));
System.out.print("\t" + resultSet.getObject("email"));
System.out.print("\t" + resultSet.getObject("birthday"));
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e2) {
e2.printStackTrace();
}
resultSet = null;
}
if (statement != null) {
try {
statement.close();
} catch (Exception e2) {
e2.printStackTrace();
}
statement = null;
}
if (connection != null) {
try {
connection.close();
} catch (Exception e2) {
e2.printStackTrace();
}
connection = null;
}
}
}
}
JDBC程序中的DriverManager用于加载驱动
DriverManager.registerDriver(Driver driver); //不建议采用这种方式
Class.forName("com.mysql.jdbc.Driver"); //建议采用这种方式
Class.forName("com.mysql.jdbc.Driver");
原因:JDBC程序中创建与数据库的连接Connection
connection = DriverManager.getConnection(url, user, password);
import com.mysql.jdbc.JDBC4Connection;
,这是一个具体的类,应该采用import java.sql.Connection;
,这是一个接口,要注意面向接口编程的思想。数据库URL
jdbc.mysql:[]//localhost:3306/test?参数名:参数值
jdbc.mysql:[]//localhost:3306/test
jdbc:sqlserver://localhost:1433; DatabaseName=test
"jdbc:oracle:thin:@127.0.0.1:1521:huangorcl
jdbc:mysql:///test
,这个前提是默认的本机和端口是3306 useUnicode=true&characterEncoding=UTF-8
,当所有的字符编码都是用的是UTF-8user=monty&password=greaesqldb
,把用户名和密码当作参数使用,在调用getConnection()方法时,放一个参数就可。JDBC程序中Statement对象用于向数据库发送SQL语句
statement = connection.createStatement();
JDBC程序中ResultSet用于代表sql语句的执行结果
resultSet = statement.executeQuery(sql);
getObject(1)
getObject("id")
,建议使用这种方法。ResultSet常用的数据类型转换表
- BIT(1) bit(1) getBoolean() getBytes() Boolean byte[]
- TINYINT getByte() Byte
- SMALLINT getShort() Short
- Int getInt() Int
- BIGINT getLong() Long
- CHAR VARCHAR LONGVARCHAR getString() String
- TEXT(clob) BLOB getClob() getBlob() Clob Blob
- DATE getDate() java.sql.Date
- TIME getTime() java.sql.Time
- TIMESTAMP getTimestamp() java.sql.Timestamp
ResultSet还提供了对结果集进行滚动的方法:
释放资源:
JDBC中的Statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句
// ---------------数据库的配置文件db.properties------------------------
driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql:///jdbc
username = root
password = 123456
// -------获取配置文件,得到连接,关闭流操作的工具类JDBCUtil.java---------
package com.hsx.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtil {
private static String driverClassName = null;
private static String url = null;
private static String username = null;
private static String password = null;
/**
* 获取配置文件,加载数据库驱动,写在静态代码块中,表示只需要执行一次
*/
static {
try {
InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(inputStream);
driverClassName = properties.getProperty("driverClassName");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driverClassName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 得到连接
* @return
* @throws Exception
*/
public static Connection getConnection() throws Exception {
Connection connection = DriverManager.getConnection(url, username, password);
return connection;
}
/**
* 释放资源
* @throws Exception
*/
public static void release(ResultSet resultSet, Statement statement, Connection connection) throws Exception {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
resultSet = null;
}
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
statement = null;
}
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
connection = null;
}
}
}
// ---------------对数据库表的CRUD操作-----------------------------
package com.hsx;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Connection;
import org.junit.Test;
import com.hsx.util.JDBCUtil;
/**
* CRUD
*
* @author hsx
*
*/
public class CRUD {
@Test
public void testAdd() throws Exception {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
statement = connection.createStatement();
String sql = "insert into user values (5, ‘hhh‘, ‘hhh‘, ‘hhh@126.com‘, ‘1990-02-25‘)";
int number = statement.executeUpdate(sql);
if (number > 0) {
System.out.println("添加成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, statement, connection);
}
}
@Test
public void testDelete() throws Exception {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
statement = connection.createStatement();
String sql = "delete from user where id = 1";
int number = statement.executeUpdate(sql);
if (number > 0) {
System.out.println("删除成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, statement, connection);
}
}
@Test
public void testUpdate() throws Exception {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
statement = connection.createStatement();
String sql = "update user set password = ‘pppp‘ where id = 3";
int number = statement.executeUpdate(sql);
if (number > 0) {
System.out.println("修改成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, statement, connection);
}
}
@Test
public void testQuery() throws Exception {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
statement = connection.createStatement();
String sql = "select * from user";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString("name"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, statement, connection);
}
}
}
PreparedStatement是Statement的子类,它的实例对象可以通过调用Connection.preparedStatement()
方法获得,相对于Statement对象而言:
package com.hsx.prepared;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
public class CRUD {
@Test
public void testAdd() throws Exception {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
String sql = "insert into user (name, password, email, birthday) values (?, ?, ?, ?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "ppp");
preparedStatement.setString(2, "ppp");
preparedStatement.setString(3, "ppp@126.com");
preparedStatement.setString(4, "1990-12-23");
int number = preparedStatement.executeUpdate();
if (number > 0) {
System.out.println("添加成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
public void testDelete() throws Exception {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
String sql = "delete from user where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 5);
int number = preparedStatement.executeUpdate();
if (number > 0) {
System.out.println("删除成功!");
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
public void testUpdate() throws Exception {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
String sql = "update user set password = ? where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "121121");
preparedStatement.setInt(2, 2);
int number = preparedStatement.executeUpdate();
if (number > 0) {
System.out.println("修改成功");
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
public void testQuery() throws Exception {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
String sql = "select * from user where name = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "hhh");
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.print(resultSet.getInt("id") + "\t" + resultSet.getString("name") + "\t" + resultSet.getString("password"));
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
}
在实际开发中,程序需要把大文本或者二进制数据保存到数据库中。
基本概念:大数据也称之为LOB(Large Objects),LOB又分为:clob和blob
对于MySQL来说只有blob,而没有clob,mysql存储大文本采用的是Text,Text和blob分别又分为:
JDBC处理大文本数据示例:
// --JDBCUtil.java文件用于获取Connection和释放流
// --xml.md和Tomcat.md文件是大文本
// --db.properties文件是数据库的基本配置文件
package com.hsx;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* 大文本的存取
*
* @author hsx
*
*/
public class Text {
private static Connection connection = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null;
public static void main(String[] args) {
//testAdd();
//testQuery();
//testUpdate();
testDelete();
}
/**
* 向数据库中插入大文本数据
*/
private static void testAdd() {
try {
connection = JDBCUtil.getConnection();
String sql = "insert into text (content) values (?)";
preparedStatement = connection.prepareStatement(sql);
URL url = Text.class.getClassLoader().getResource("xml.md");
String pathname = url.getPath();
File file = new File(pathname);
preparedStatement.setCharacterStream(1, new FileReader(file), file.length());
int num = preparedStatement.executeUpdate();
if (num > 0) {
System.out.println("添加成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
/**
* 查询大文本数据,并写到磁盘上
*/
private static void testQuery() {
try {
connection = JDBCUtil.getConnection();
String sql = "select content from text where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 2);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
Reader reader = resultSet.getCharacterStream("content");
FileWriter fileWriter = new FileWriter("D:/xml.md");
char[] c = new char[1024];
int len = -1;
while ((len = reader.read(c)) != -1) {
fileWriter.write(c, 0, len);
}
reader.close();
fileWriter.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
/**
* 修改大文本数据
*/
private static void testUpdate() {
try {
connection = JDBCUtil.getConnection();
String sql = "update text set content = ? where id = ?";
preparedStatement = connection.prepareStatement(sql);
URL url = Text.class.getClassLoader().getResource("Tomcat.md");
String pathname = url.getPath();
File file = new File(pathname);
preparedStatement.setCharacterStream(1, new FileReader(file), file.length());
preparedStatement.setInt(2, 2);
int num = preparedStatement.executeUpdate();
if (num > 0) {
System.out.println("修改成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
/**
* 把大文本数据从数据库删除
*/
private static void testDelete() {
try {
connection = JDBCUtil.getConnection();
String sql = "delete from text where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 2);
int num = preparedStatement.executeUpdate();
if (num > 0) {
System.out.println("删除成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
}
JDBC处理二进制数据示例:
// --JDBCUtil.java文件用于获取Connection和释放流
// --b.jbg和1.jpg文件是二进制文件
// --db.properties文件是数据库的基本配置文件
package com.hsx;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class Blob {
private static Connection connection = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null;
public static void main(String[] args) {
//testAdd();
//testQuery();
//testUpdate();
testDelete();
}
/**
* 向数据库中添加二进制文件
*/
private static void testAdd() {
try {
connection = JDBCUtil.getConnection();
String sql = "insert into blobdemo (content) values (?)";
preparedStatement = connection.prepareStatement(sql);
URL url = Blob.class.getClassLoader().getResource("b.jpg");
String pathname = url.getPath();
File file = new File(pathname);
preparedStatement.setBinaryStream(1, new FileInputStream(file), file.length());
int num = preparedStatement.executeUpdate();
if (num > 0) {
System.out.println("添加成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
/**
* 从数据库中查询二进制数据,并写到磁盘中
*/
private static void testQuery() {
try {
connection = JDBCUtil.getConnection();
String sql = "select content from blobdemo where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 1);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
InputStream inputStream = resultSet.getBinaryStream("content");
FileOutputStream fileOutputStream = new FileOutputStream("D:/b.jpg");
byte[] b = new byte[1024];
int len = -1;
while ((len = inputStream.read(b)) != -1) {
fileOutputStream.write(b, 0, len);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
/**
* 修改数据中二进制文本数据
*/
private static void testUpdate() {
try {
connection = JDBCUtil.getConnection();
String sql = "update blobdemo set content = ? where id = ?";
preparedStatement = connection.prepareStatement(sql);
URL url = Blob.class.getClassLoader().getResource("1.jpg");
String pathname = url.getPath();
File file = new File(pathname);
preparedStatement.setBinaryStream(1, new FileInputStream(file), file.length());
preparedStatement.setInt(2, 1);
int num = preparedStatement.executeUpdate();
if (num > 0) {
System.out.println("修改成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
/**
* 删除数据库中二进制数据
*/
private static void testDelete() {
try {
connection = JDBCUtil.getConnection();
String sql = "delete from blobdemo where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 1);
int num = preparedStatement.executeUpdate();
if (num > 0) {
System.out.println("删除成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
}
业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。
一般常用的方法有:
package com.hsx;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
public class Batch {
private static Connection connection = null;
private static Statement statement = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null;
public static void main(String[] args) {
//testBatchByStatement();
testBatchByPreparedStatement();
}
/**
* 使用Statement处理批处理
*/
private static void testBatchByStatement() {
try {
connection = JDBCUtil.getConnection();
statement = connection.createStatement();
String sql1 = "insert into batchbdemo (name) values (‘xiaoshan‘)";
String sql2 = "insert into batchbdemo (name) values (‘hello‘)";
String sql3 = "insert into batchbdemo (name) values (‘world‘)";
statement.addBatch(sql1);
statement.addBatch(sql2);
statement.addBatch(sql3);
statement.executeBatch(); //执行批处理
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, statement, connection);
}
}
/**
* 使用PreparedStatement处理批处理,包括对内存溢出的处理
*/
private static void testBatchByPreparedStatement() {
try {
connection = JDBCUtil.getConnection();
String sql = "insert into batchbdemo (name) values (?)";
preparedStatement = connection.prepareStatement(sql);
for (int i = 1; i <= 10000200; i++) {
preparedStatement.setString(1, "a" + i);
preparedStatement.addBatch();
if (i % 1000 == 0) {
preparedStatement.executeBatch();
preparedStatement.clearBatch(); //清除缓存
}
}
preparedStatement.executeBatch(); // 这句是最后对不能被1000整除的200的数据的批处理
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, statement, connection);
}
}
}
注:采用PreparedStatement.addBatch()实现批处理的优缺点即应用场合:
示例:
package com.hsx;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 获取出入的记录的主键:insert语句时才有效,要求数据库能自动生成主键
* @author hsx
*
*/
public class GenAutoKey {
private static Connection connection = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null;
public static void main(String[] args) {
getGenAutoKey();
}
private static void getGenAutoKey() {
try {
connection = JDBCUtil.getConnection();
String sql = "insert into genautokey (name) values (?)";
preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); // Statement.RETURN_GENERATED_KEYS是默认的,可以不用加
preparedStatement.setString(1, "admin");
preparedStatement.executeUpdate();
resultSet = preparedStatement.getGeneratedKeys(); //这里返回的是id的记录,不能用resultSet.getObject("id");
if (resultSet.next()) {
System.out.println(resultSet.getObject(1));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
}
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。将封装好的复杂逻辑放在数据库中执行。
示例:
// 存储过程:
/*
delimiter $$
CREATE PROCEDURE `demoSp`(IN inputParam VARCHAR(255), INOUT inOutParam varchar(255))
BEGIN
SELECT CONCAT(‘hello---‘, inputParam) into inOutParam;
END $$
*/
package com.hsx;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Types;
/**
* 调用存储过程
* @author hsx
*
*/
public class Procddure {
private static Connection connection = null;
private static CallableStatement callableStatement = null;
private static ResultSet resultSet = null;
public static void main(String[] args) {
procedure();
}
private static void procedure() {
try {
connection = JDBCUtil.getConnection();
String sql = "{call demosp(?, ?)}";
callableStatement = connection.prepareCall(sql);
callableStatement.setString(1, "xiaosan");
callableStatement.registerOutParameter(2, Types.VARCHAR);
callableStatement.execute();
System.out.println(callableStatement.getString(2));
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, callableStatement, connection);
}
}
}
事务的概念:事务指在逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功,比如转账的操作。
当JDBC程序向数据库获取一个Connection对象时,默认情况下这个Connection对象会自动向数据库提交在它上面的sql语句。若想关闭这种默认方式,让多条sql在一个事务中执行,connection.setAutoCommit(false)
。JDBC控制事务语句:
/*
create databases jdbc character set utf8 collate utf8_general_ci;
use jdbc;
create table account(
id int primary key auto_increment,
name varchar(40),
money float
)character set utf8 collate utf8_general_ci;
insert into account (name, money) values (‘aaa‘, 1000);
insert into account (name, money) values (‘bbb‘, 1000);
insert into account (name, money) values (‘ccc‘, 1000);
*/
package com.hsx;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* JDBC处理事务
* @author hsx
*
*/
public class Tranaction {
private static Connection connection = null;
private static PreparedStatement preparedStatement = null;
private static ResultSet resultSet = null;
public static void main(String[] args) {
tranaction();
}
private static void tranaction() {
try {
connection = JDBCUtil.getConnection();
connection.setAutoCommit(false); //开启事务
String sql1 = "update account set money=money+100 where name=‘aaa‘";
preparedStatement = connection.prepareStatement(sql1);
preparedStatement.executeUpdate();
//int i = 1 / 0;
String sql2 = "update account set money=money-100 where name=‘bbb‘";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
connection.commit();
} catch (Exception e) {
try {
connection.rollback();
connection.commit(); //关闭事务,只用commit才能关闭事务
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
}
示例:
package com.hsx;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
/**
* JDBC处理事务
* @author hsx
*
*/
public class Tranaction {
public static void main(String[] args) {
tranaction();
}
private static void tranaction() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Savepoint savepoint = null;
try {
connection = JDBCUtil.getConnection();
connection.setAutoCommit(false); //开启事务
String sql1 = "update account set money=money+100 where name=‘aaa‘";
preparedStatement = connection.prepareStatement(sql1);
preparedStatement.executeUpdate();
//设置回滚点
savepoint = connection.setSavepoint();
//int i = 1 / 0;
String sql2 = "update account set money=money-100 where name=‘bbb‘";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
int i = 1 / 0;
String sql3 = "update account set money=money+1000 where name=‘ccc‘";
preparedStatement = connection.prepareStatement(sql3);
preparedStatement.executeUpdate();
connection.commit();
} catch (Exception e) {
try {
connection.rollback(savepoint);
connection.commit(); //关闭事务,只用commit才能关闭事务
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
}
多个线程开启各自的事务操作数据库中数据时,数据库系统要负责隔离性操作,以保证各个线程在获取数据时的准确性。如果不考虑隔离性,可能会引发问题,如:
数据库共定义了四种隔离级别:
设置事务的隔离级别:set tranaction isolation level xxxxx
查询当前事务隔离级别:select @@tx_isolation
Connection中的setTransactionIsolation(int level)用于设置隔离级别
level:表示Connection中的常量
先设置隔离级别,再开启事务:
示例:
// ---------要通过开启一个MySQL的线程配合测试-------
package com.hsx;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.print.attribute.standard.MediaSize.ISO;
/**
* 实现事务隔离
* @author hsx
*
*/
public class Isolaction {
public static void main(String[] args) {
isolation();
}
private static void isolation() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); //设置事务的隔离级别
connection.setAutoCommit(false); //设置事务
String sql = "select money from account where name = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "aaa");
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
System.out.println(resultSet.getObject(1));
}
Thread.sleep(10000);
if (resultSet.next()) {
System.out.println(resultSet.getObject(1));
}
connection.commit();
} catch (Exception e) {
try {
connection.rollback();
connection.commit();
} catch (Exception e2) {
e2.printStackTrace();
}
e.printStackTrace();
} finally {
JDBCUtil.release(resultSet, preparedStatement, connection);
}
}
}
应用程序直接获取连接Connection的缺点:用户每次请求都需要向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。如果网站一天10万次的访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机。
简单的数据库连接写法示例:
package com.hsx;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.LinkedList;
public class SimpleConnectionPool {
private static LinkedList<Connection> pool = new LinkedList<Connection>();
private static String driverClassName = "com.mysql.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/jdbc";
private static String username = "root";
private static String password = "123456";
static {
try {
//加载驱动
Class.forName(driverClassName);
//创建一定数量的连接放入连接池中 10
for (int i = 0; i < 10; i++) {
Connection connection = DriverManager.getConnection(url, username, password);
pool.add(connection);
}
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public synchronized static Connection getConnection() {
return pool.removeFirst(); //得到第一个连接,并从list中删除
}
public static void release(Connection connection) {
pool.addLast(connection); //连接池用完了再放到list中
}
}
编写连接池需要实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
实现DataSource接口,并实现连接池功能的步骤:
上步骤的关键点:Collection保证将自己返回到LinkedList中是此处编程的难点!具体操作如下:
对已有的类进行增强(mysql中的com.mysql.jdbc.Connection实现的close方法。增强为调用close方法时,不是关闭连接,而是把连接放回对应的LinkedList中),怎么增强:
写一个子类,覆盖父类中对应的方法(要增强的方法)
现在很多Web服务器(Weblogic、WebSphere、Tomcat)都提供了DataSource的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称为数据源,数据源中都包含了数据连接池的实现。
也有一些开源组织提供了数据源的独立实现:
实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。我们在编程时,也应该尽量使用这些数据源的实现,以提升程序的数据库访问性。
//-----------db.properties-----------------------------
driverClassName= com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbc
username = root
password = 123456
initialSize = 10
maxActive = 50
maxIdle = 20
minIdle = 5
maxWait = 60000
connectionProperties = useUnicode=true;characterEncoding=UTF-8
defaultAutoCommit = true
#defaultReadOnly =
#defaultTransactionIsolation = READ_UNCOMMITED
// -------------利用BasicDataSourceFactory创建数据源-------------------
package com.hsx.dbcp;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class JDBCUtil_dbcp {
private static DataSource dataSource;
static {
try {
InputStream inputStream = JDBCUtil_dbcp.class.getClassLoader().getResourceAsStream("db.properties");
Properties props = new Properties();
props.load(inputStream);
BasicDataSourceFactory basicDataSourceFactory = new BasicDataSourceFactory();
dataSource = basicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws Exception {
return dataSource.getConnection();
}
public static void release(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
resultSet = null;
}
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
statement = null;
}
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
connection = null;
}
}
}
拷贝jar包(c3p0-0.9.1.2.jar和c3p0-0.9.1.2-jdk1.3.jar)另外Oracle还需用到的jar包:c3p0-oracle-thin-extras-0.9.1.2.jar;如果需要用配置文件,在类路径下创建一个名为c3p0-config.xml的配置文件。
package com.hsx.c3p0;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtil_c3p0 {
private static ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
static {
try {
comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc");
comboPooledDataSource.setUser("root");
comboPooledDataSource.setPassword("123456");
comboPooledDataSource.setMaxPoolSize(40);
comboPooledDataSource.setMinPoolSize(10);
comboPooledDataSource.setInitialPoolSize(50);
} catch (Exception e) {
throw new ExceptionInInitializerError();
}
}
public static Connection getConnection() throws Exception {
return comboPooledDataSource.getConnection();
}
public static void release(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
resultSet = null;
}
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
statement = null;
}
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
connection = null;
}
}
}
// -----------配置文件c3p0-config.xml[注;这个配置文件必须是这个名字]-----------
<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
<named-config name="jdbc">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///jdbc</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquireIncrement">10</property>
<property name="initialPoolSize">30</property>
<property name="maxPoolSize">40</property>
<property name="minPoolSize">5</property>
<property name="maxStatements">1000</property>
<property name="maxStatementsPerConnection">100</property>
</named-config>
</c3p0-config>
// -------------通过c3p0获取数据库连接池(用到配置文件)--------------------
package com.hsx.c3p0;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 通过c3p0获取数据库连接池(用到配置文件)
* @author hsx
*
*/
public class JDBCUtil_C3p0Demo {
private static ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("jdbc");
public static Connection getConnection() throws Exception {
return comboPooledDataSource.getConnection();
}
public static void release(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
resultSet = null;
}
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
statement = null;
}
if (connection != null) {
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
connection = null;
}
}
}
在Web应用META-INF目录下建立一个context.xml的配置文件:
<?xml version="1.0" encoding="utf-8"?>
<Context>
<Resource name="jdbc/jdbc"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="123456"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql:///jdbc"
maxActive="8"
maxIdle="4"/>
</Context>
需要把数据库驱动拷贝到Tomcat安装目录/lib中(部拷贝,会出现找不到驱动的错误),
package com.hsx.tomcat;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
public class DataSourceDemo extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//JDNI:Java Naming and Directory Interface Java命名与目录服务
try {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource dataSource = (DataSource) envCtx.lookup("jdbc/jdbc");
Connection connection = dataSource.getConnection();
String sql = "select * from testdbcp";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("name"));
}
resultSet.close();
preparedStatement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
标签:
原文地址:http://blog.csdn.net/hsx1612727380/article/details/51297941