1.事务小议
事务指逻辑上的一组操作,组成这组操作的各单元要么全部成功,要么全部不成功。
例如A——B转账,对于如下两条SQL语句:
update from account set money=money+100 where name='b';
update from account set money=money-100 where name='a';
通常事务具有如下几大特性:
- 原子性——原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性——事务必须是数据库从一个一致性状态换到另一个以后仔细状态。
- 隔离性——事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
- 持久性——持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
如何使用JDBC管理事务?当一个连接对象被创建时,默认情况下JDBC是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚
,如想多条SQL在同一事务中,可使用如下语句
将自动提交设置为false
Connection.setAutoCommit(false); 设置事务回滚 Connection.rollbcak(); 提交事务 Connection.commit();
public class SQLTest2 {
public static void main(String[] args) {
String name = "sun";
String password = "1234" ;//拼接,从而通过数据库的检查
new SQLTest2().mysql(name, password);
}
private void mysql(String name, String password) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
//用户名
String userName="root";
//密码
String psw = "mysql1991";
// 连接数据库的url
String url = "jdbc:mysql://localhost:3306/mytest";
try {// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建 数据库 连接对象
conn = DriverManager.getConnection(url,userName,psw);
//设置默认提交方式为false
conn.setAutoCommit(false);
// 3创建PreparedStatement对象
String sql2 = "select * from t_user where name=? and password=?";
pstmt = conn.prepareStatement(sql2);
pstmt.setString(1, name);
pstmt.setString(2, password);
//4 获取ResultSet对象
rs=pstmt.executeQuery();
if (rs.next()) {
System.out.println("用户名:" + rs.getString("name") + " 密码:"
+ rs.getString("password"));
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
//提交事务
conn.commit();
} catch (Exception e) {
//事务回滚
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.连接池简介
连接池的基本思路是在系统初始化时,将数据库连接对象存储在程序的内存中,当用户需要访问数据时,直接从连接池中取出一个已建立的空闲连接对象,
使用完毕后吗,将连接放回连接池中,以供下一个用户请求访问使用。而连接的建立、断开都由连接池自身来管理。
常用的数据库连接池有JNDI、Apache的Jakarta和dbcp等。下面举例用dbcp
在连接池中的几个十分重要的参数说明:
参数 | 缺省值 | 说明 |
initialSize | 0 | 线程池启动时初始化的连接数 |
maxActive | 8 | 最大活动连接数,如果非正整数,则不做限制 |
maxIdle | 8 | 最大空闲连接数 |
minIdle | 0 | 最小空闲连接数 |
maxWait | indeFinitely | (在没有连接可用时)连接池等待一个数据连接可用时以毫秒计 的最大等待时间,超时以后跑出异常,-1则无限等待 |
dbcp依赖于commons-pool来存储连接对象。BasicDataSource默认使用GenericObjectPool来管理连接对象。
dbcp中的一些名词概念:
名词 | 说明 |
对象池(ObjectPool接口) | 可以把它认为是一种容器,用来装池对象的,并且包含了用来创建池对象的工厂对象 |
池对象 | 就是要放到池容器中的对象,理论上可以是任何对象 |
对象池工厂(OBjectPoolFactory接口) | 用来创建对象池的工厂 |
池对象工厂(PoolableObjectFactory接口) | 用来创建池对象,将不用的池对象进行钝化(passivateObject),对要使用的池对象(activeObject), 对池对象进行验证(validateObject),对有问题的池对象进行销毁(destroyObject)等工作 |
使用dbcp的几大步骤:
- 在src文件中建立properties文件,文件中设置了一些属性
- 通过BasicDataSource创建Connection对象
- 根据Connection对象操作数据库
一下代码采用连接池操作数据库,dbcp.properties文件,这个是配置文件
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mytest
username=root
password=mysql1991
#<!--初始化连接-->
dataSource.initialSize=20
#<!--最大空闲连接-->
dataSource.maxIdle=20
#<!--最小空闲连接-->
dataSource.minIdle=5
#最大连接数量
dataSource.maxActive=100
#是否自动回收超时连接
dataSource.removeAbandoned=true
#超时时间(以秒数为单位)
#设置超时时间有一个要注意的地方,超时时间=现在的时间-程序中创建Connection的时间,
#如果maxActive比较大,比如超过100,那么removeAbandonedTimeout可以设置长一点比如180,
#也就是三分钟无响应的连接进行回收,当然应用的不同设置长度也不同。
dataSoure.removeAbandonedTimeout=180
#<!--超时等待时间以毫秒为单位-->
#maxWait代表当Connection用尽了,多久之后进行回收丢失连接
dataSource.maxWait=100
创建完properties文件后就要用Properties类来解析properties文件,如下:
Properties pro = new Properties();
InputStream in = DbcpTest.class.getClassLoader().getResourceAsStream("bcp.properties");
pro.load(in);
下面使用连接池技术查询表结构
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
public class DbcpTest {
public static void main(String[] args) throws Exception {
// 解析properties文件
Properties p = new Properties();
InputStream in = DbcpTest.class.getClassLoader().getResourceAsStream(
"dbcp.properties");
p.load(in);
DataSource ds = BasicDataSourceFactory.createDataSource(p);
Connection conn = ds.getConnection();
String sql = "select * from t_user";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String name = rs.getString("name");
String password = rs.getString("password");
System.out.println("用户名:" + name + " 密码:" + password);
}
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
}
}