Javaweb学习笔记(JDBC处理事务与数据库连接池)
JDBC处理事务
在数据库操作中,一项事务是由一条或多条操作数据的SQL语句组成的一个不可分割的工作单元。针对JDBC处理事务的操作在Connection接口中,提供了3个相关的方法。具体如下:
(1)setAutoCommit(Boolean autoCommit):设置是否自动提交事务
(2)commit():提交事务
(3)rollback():撤销事务
默认情况下,事务是自动提交的。
案例:
(1)首先创建一个chapter02数据库,并在该数据库下创建名为accout的表,向表中插入若干数据
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);
(2)新建工程chapter02,新建一个类,该类用于模拟两个账号之间的转账业务。
package cn.itcast.jdbc.example;
import java.sql.*;
import cn.itcast.jdbc.example.utils.*;
public class Example08 {
public static void main(String[] args){
String outAccount="aaa";
String inAccount="bbb";
int amount=200;
Connection conn=null;
PreparedStatement pstmt1=null;
PreparedStatement pstmt2=null;
try{
conn=JDBCUtils.getConnection();
//关闭事务自动提交
conn.setAutoCommit(false);
String sql="update account set money=money-? where"
+" name=? and money>=?";
pstmt1=conn.prepareStatement(sql);
pstmt1.setDouble(1, amount);
pstmt1.setString(2, outAccount);
pstmt1.setDouble(3, amount);
pstmt1.executeLargeUpdate();
String sql2="update account set money=money+? where"
+" name=?";
pstmt2=conn.prepareStatement(sql2);
pstmt2.setDouble(1, amount);
pstmt2.setString(2, inAccount);
pstmt2.executeLargeUpdate();
conn.commit();
System.out.println("转账成功");
}catch(Exception e){
try{
conn.rollback();
System.out.println("转账失败");
}catch(SQLException e1){
e1.printStackTrace();
}
}finally{
if(pstmt1!=null){
try{
pstmt1.close();
}catch(SQLException e){
e.printStackTrace();
}
pstmt1=null;
}
if(pstmt2!=null){
try{
pstmt2.close();
}catch(SQLException e){
e.printStackTrace();
}
pstmt2=null;
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
conn=null;
}
}
}
}
数据库连接池
在JDBC编程中,每次创建和断开Connection对象都会消耗一定的时间和IO资源,这是因为在Java程序与数据库之间建立连接时,数据库段要验证用户名和密码没并且在这个连接分配资源,Java程序则要把代表连接的java.conn.Connection对象加载到内存中,会加大建立数据库的开销。
为了解决问题,工程师们提出了数据库连接池技术。数据库连接池负责分配、管理和释放数据库连接,允许应用程序重复使用现有的数据库连接,而不是重新建立。
数据库连接池在初始化时会创建一定数量数据库连接放到数据库连接池中,当应用程序访问数据库时并不是直接创建,而是向连接池“申请”Connection。如果池中有空闲的Connection,则将其返回。
DataSource接口
为了获取数据库连接对象JDBC提供了javax.sql.DataSource接口,他负责与数据库进行连接,并定义了返回值为Connection对象的方法:
Connection getConnection()
Connection getConnection(String username,String password)
第一个是通过无参的方式创建数据库连接,第二种是通过传入登录信息的方式建立数据库连接。
人们把实现了java.sql.DataSource接口的类称为数据源,数据源即数据的来源,在数据源中存储了所有建立数据库的连接信息。
DBCP数据源
单独使用DBCP数据源时,需要在应用程序中导入两个jar包
commons-dbcp.jar包
commons-dbcp.jar包是DBCP数据源的实现包,包含所有操作数及句酷连接信息和数及句酷连接的初始化信息的方法,并实现了DataSource接口的getConnection()方法。
commons-pool.jar包
commons-pool.jar包是DBCP数据库连接池实现的依赖包,为commons-dbcp.jar包中的方法提供了支持。BasicDataSource是DataSource接口的实现类,主要包括设置数据源对象的方法。
方法名称 | 功能描述 |
---|---|
void setDriverClassName(String driverClassName) | 设置连接数据库的驱动名称 |
void setUrl(String url) | 设置连接数据库的路径 |
void serUsername(String username) | 设置数据库的登录账号 |
void setPassword(String password) | 设置数据库的登录密码 |
void setInitialSize(int initialSize) | 设置数据库连接池初始化的连接数目 |
void setMaxActive(int maxIdle) | 设置数据库连接池最大活跃的连接数目 |
void setMinIdle(int minIdle) | 设置数据库连接池最小闲置的连接数目 |
Connection getConnection() | 从连接池中获取一个数据库连接 |
当使用DBCP数据源时,首先要创建数据源对象,数据源对象的创建方式有两种:
1.通过BasicDataSource类直接创建数据源对象
使用BasicDataSource类创建一个数据源对象,手动给数据源对象设置属性值,然后获取数据库连接对象。
package cn.itcast.jdbc.example;
import java.sql.*;
import javax.sql.*;
import org.apache.commons.dbcp2.*;
public class Example09 {
public static DataSource ds=null;
static{
BasicDataSource bds=new BasicDataSource();
bds.setDriverClassName("com.mysql.cj.jdbc.Driver");
bds.setUrl("jdbc:mysql://localhost:3306/chapter02?useSSL=true&serverTimezone=GMT");
bds.setUsername("root");
bds.setPassword("123456");
bds.setInitialSize(5);
bds.setMaxTotal(5);
ds=bds;
}
public static void main(String[] args)throws SQLException{
Connection conn=ds.getConnection();
DatabaseMetaData metData=conn.getMetaData();
System.out.println(metData.getURL()
+",Username="+metData.getUserName()
+",DriverName="+metData.getDriverName()
);
}
}
2.通过读取配置文件创建数据源对象
使用BasicDataSourceFactory工厂类读取配置文件,创建数据源对象,然后获取连接对象。
示例:
package cn.itcast.jdbc.example;
import java.sql.*;
import javax.sql.*;
import org.apache.commons.dbcp2.*;
public class Example09 {
public static DataSource ds=null;
static{
BasicDataSource bds=new BasicDataSource();
bds.setDriverClassName("com.mysql.cj.jdbc.Driver");
bds.setUrl("jdbc:mysql://localhost:3306/chapter02?useSSL=true&serverTimezone=GMT");
bds.setUsername("root");
bds.setPassword("123456");
bds.setInitialSize(5);
bds.setMaxTotal(5);
ds=bds;
}
public static void main(String[] args)throws SQLException{
Connection conn=ds.getConnection();
DatabaseMetaData metData=conn.getMetaData();
System.out.println(metData.getURL()
+",Username="+metData.getUserName()
+",DriverName="+metData.getDriverName()
);
}
}
C3P0数据源
C3P0是目前最流行的开源数据连接池之一,它实现了DataSource数据源接口,支持JDBC2和JDBC3的标准规范,易于扩展并且性能优越,著名的开源框架Hibernate和Spring使用的都是该数据源。
ComboPoolDataSource类的常用方法:
方法名称 | 功能描述 |
---|---|
void setDriverClass() | 设置连接数据库的驱动名称 |
void setJdbcUrl() | 设置连接数据库的路径 |
void setUser() | 设置数据库的登录账号 |
void serPassword() | 设置数据库登录密码 |
void setMaxPoolSize() | 设置数据库连接池最大的连接数目 |
void setMinPoolSize() | 设置数据库连接池最小的连接数目 |
void setInitialPoolSize() | 设置数据库连接池初始化的连接数目 |
Connection getConnection() | 从数据库连接池中获取一个连接 |
当时用C3P0数据源时,首先要创建数据源对象,创建数据源对象可以使用ComboPoolDataSource类,该类有两个构造方法,分贝是ComboPoolDataSource()和ComboPoolDataSource(String configName)。
示例:
1.通过ComboPoolDataSource类直接创建数据源对象
使用ComboPoolDataSource类直接创建一个数据源对象,手动给数据源对象设置属性值,然后获取数据库连接对象。
package cn.itcast.jdbc.example;
import java.sql.*;
import javax.sql.*;
import com.mchange.v2.c3p0.*;
public class Example11 {
public static DataSource ds=null;
//初始化C3P0
static{
ComboPooledDataSource cpds=new ComboPooledDataSource();
//设置连接数据库所需要的配置信息
try{
cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/chapter02?useSSL=true&serverTimezone=GMT");
cpds.setUser("root");
cpds.setPassword("123456");
//设置数据库连接参数
cpds.setInitialPoolSize(5);
cpds.setMaxPoolSize(15);
ds=cpds;
}catch(Exception e){
throw new ExceptionInInitializerError(e);
}
}
public static void main(String arg[])throws SQLException{
System.out.println(ds.getConnection());
}
}
2.通过读取配置文件创建数据源对象
通过ComboPoolDataSource(String configName)构造方法读取c3p0-config.xml配置文件,创建数据源对象,然后获取数据库连接对象。
(1)在src根目录下创建一个c3p0-config.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="user">root</property>
<property name="password">123456</property>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">
jdbc:mysql://localhost:3306/chapter01</property>
<property name="checkoutTimeout">60000</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
<name-config name="myconfig">
<property name="user">root</property>
<property name="password">123456</property>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">
jdbc:mysql://localhost:3306/chapter01</property>
<property name="initialPoolSize">5</property>
<property name="maxIdleTime">15</property>
</name-config>
</c3p0-config>
(2)在cn.itcast.example包下创建一个Example05
package cn.itcast.jdbc.example;
import java.sql.*;
import javax.sql.*;
import com.mchange.v2.c3p0.*;
public class Example12 {
public static DataSource ds=null;
static{
ComboPooledDataSource cpds = new ComboPooledDataSource("config");
ds=cpds;
}
public static void main(String[] args) throws SQLException{
System.out.print(ds.getConnection());
}
}