一、事务
1.事务概念
事务是指一组最小逻辑操作单元,里面有多个操作。组成事务的每一部分必须同时提交成功。如果有一个操作失败,整个操作就回滚。
2.事务ACID特性
- 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency)事务必须使数据库从一个一致状态变换到另外一个一致性状态。
- 隔离性(Isolation)事务的隔离性是指多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所打扰,多个并发事务之间要相互隔离。
- 持久性(Durability)事务是指一个事务一旦被提交,它对数据库中的数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
3.转账的一个小案例
默认情况下,Connection对象处于自动提交模式下,这意味着它在执行每个语句后都会自动提交更改。
connection.setAutoCommit(false);//设置成手动提交事务
connection.rollback();//回滚事务
connection.commit();//手动提交事务
//我们把扣钱和加钱放到一个事务中,统一手动提交,如果遇到异常我们就回滚事务;没有遇到异常就正常提交
Connection connection =null;
PreparedStatement preparedStatement1 =null;
PreparedStatement preparedStatement2 =null;
try {
//张三给李四转钱
connection = JDBCUtils.getConnection();
connection.setAutoCommit(false);//设置成手动提交事务
//张三的账户要扣钱
String sql1="update users set money=money-1000 where username='张三'";
preparedStatement1 = connection.prepareStatement(sql1);
preparedStatement1.execute();
//李四的账户要加钱
String sql2="update users set money=money+1000 where username='李四'";
preparedStatement2 = connection.prepareStatement(sql2);
preparedStatement2.execute();
} catch (Exception e) {
//转账途中,如果遇到异常就回滚事务
try {
connection.rollback();//回滚事务
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
try {
connection.commit();//手动提交事务
} catch (SQLException e) {
e.printStackTrace();
}
try {
//释放资源
connection.close();
preparedStatement1.close();
preparedStatement2.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
4.事务的隔离级别
(1).不考虑隔离性会出现的读问题
脏读:在一个事务中读取到另一个事务没有提交的数据。
不可重复读:在一个事务中,两次查询的结果不一致(针对的update操作)。不可重复读是指在数据库访问中,一个事务范围内两次相同的查询却返回了不同的数据。
虚读:在一个事务中,两次查询的结果不一致(针对的insert操作),无法演示出来,MySql已经默认避免了。
(2).MySQL有四种隔离级别
隔离级别 | |
---|---|
read uncommitted读未提交 | 上面三种问题都会出现 |
read committed读已提交 | 可以避免脏读的发生 Oracle 默认界别 |
repeatable read可重复读 | 可以避免脏读和不可重复读的发生 MySQL 默认级别 |
serializable串行化 | 可以避免所有的问题 |
(3).开启事务
start transaction;
(4).设置数据库的隔离级别
set session transaction isolation level read uncommitted;
(5).查看数据库的隔离级别
select @@tx_isolation;
(6).四种隔离级别的效率
read uncommitted>read committed>repeatable read>serializable
(7).四种隔离级别的安全性
read uncommitted<read committed<repeatable read<serializable
(8).开发中绝对不允许脏读发生.
mysql中默认级别:repeatable read
oracle中默认级别:read committed
(9).java中控制隔离级别
设置数据库的隔离级别
connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
二、连接池
1.连接池:存放有一定数量的连接对象,以便重复利用这个连接对象
2.为什么会有连接池?
因为建立数据库连接是一件非常耗时,耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,使用完毕后再归还到连接池中。
3.市面上常见数据库连接池产品:DBCP、C3P0、阿里德鲁伊
(一)DBCP(DataBase Connection Pool)数据库连接池
是Java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。
1.先导入DBCP的两个jar包,当然数据驱动jar包不能少
2.开始编码
- 硬编码:所有的数据库参数,通过代码来设置
//创建连接池
BasicDataSource bs = new BasicDataSource();
//配置信息
bs.setDriverClassName("com.mysql.jdbc.Driver");
bs.setUrl("jdbc:mysql://localhost:3306/mydb");
bs.setUsername("root");
bs.setPassword("101721");
Connection connection = bs.getConnection();
- 采用配置文件的方式
//采用配置文件的方式,来使用DBCP
Properties properties = new Properties();
properties.load(new FileReader("src/dbcp.properties"));
//创建一个工厂
DataSource ds = new BasicDataSourceFactory().createDataSource(properties);
Connection connection = ds.getConnection();
(二)C3P0(DataBase Connection Pool)数据库连接池
C3P0是一个开源的JDBC连接池;它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展;目前使用它的开源项目有Hibernate、Spring等。
C3P0与DBCP区别:DBCP没有自动回收空闲连接的功能,C3P0有自动回收空闲连接的功能
1.导入C3P0的一个jar包
2.开始编码
- 硬编码
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
ds.setUser("root");
ds.setPassword("101721");
Connection connection = ds.getConnection();
- 采用配置文件的方式
采用配置文件的方式,来使用C3P0
C3P0对配置文件有以下要求:
(1).配置文件的名称是固定的c3p0.properties 或者 c3p0-config.xml
(2).配置文件必须放在src目录下
ComboPooledDataSource ds = new ComboPooledDataSource();
Connection connection = ds.getConnection();
(三)Druid(DataBase Connection Pool)数据库连接池
DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池。
1.导入Druid的一个jar包
2.开始编码
- 硬编码
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/mydb");
ds.setUsername("root");
ds.setPassword("101721");
DruidPooledConnection connection = ds.getConnection();
- 采用配置文件的方式
Properties properties = new Properties();
properties.load(new FileReader("druid.properties"));
//通过一个工厂类,创建一个数据源
DataSource ds = new DruidDataSourceFactory().createDataSource(properties);
Connection connection = ds.getConnection();
三、DBUtils
Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。
1.使用步骤
1.导入jar包
2.创建一个queryRunner类
(queryRunner作用:操作sql语句)
构造方法:new QueryRunner(DataSource ds);
3.编写sql
4.执行sql
2.DML操作
//Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,
//1.导入DBUtils的jar包
//2.创建 QueryRunner对象
Properties properties = new Properties();
properties.load(new FileReader("src/druid.properties"));
DataSource dataSource = new DruidDataSourceFactory().createDataSource(properties);
QueryRunner queryRunner = new QueryRunner(dataSource);
//进行DML,返回值:你影响的行数
int i = queryRunner.update("insert into user(username,password) values(?,?)", "杨大哥", "888");
if(i>0){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
3.DQL操作
//查询
//参数2,将查询的结果封装起来
//BeanListHandle把从数据库查出来的多条数据,封装到对象里面,在把对象放到集合里
List<User> list = queryRunner.query("select * from user", new BeanListHandler<User>(User.class));
System.out.println(list);
//BeanHandle查询一条结果,把这个结果封装到对象里面
User user = queryRunner.query("select * from user", new BeanHandler<User>(User.class));
System.out.println(user);
//MapHandle()把查询的结果封装到Map集合里面
Map<String, Object> map = queryRunner.query("select * from user", new MapHandler());
System.out.println(map);
Object username = map.get("username");
System.out.println(username);
Object password = map.get("password");
System.out.println(password);
System.out.println(map.size());