事务的特性
原子性
指的是 事务中包含的逻辑, 不可分割.
一致性
指的是 事务执行前后. 数据完整性
隔离性
指的是 事务在执行期间不应该受到其他事务的影响
持久性
指的是 事务执行成功, 那么数据应该持久保存到磁盘上.
事务的安全隐患
不考虑隔离级别设置, 那么会出现以下问题.
读
脏读 不可重读读 幻读.
脏读
一个事务读到另外一个事务还未提交的数据
不可重复读
一个事务读到了另外一个事务提交的数据 , 造成了前后两次查询结果不一致.
可串行化
如果有一个连接的隔离级别设置为了串行化 , 那么谁先打开了事务, 谁就有了先执行的权利, 谁后打开事务, 谁就只能得着, 等前面的那个事务, 提交或者回滚后, 才能执行. 但是这种隔离级别一般比较少用. 容易造成性能上的问题. 效率比较低.
按效率划分, 从高到低
读未提交 > 读已提交 > 可重复读 > 可串行化
按拦截程度 , 从高到底
可串行化 > 可重复读 > 读已提交 > 读未提交
事务总结
需要掌握的
在代码里面会使用事务
- conn.setAutoCommit(false);
- conn.commit();
- conn.rollback();
事务只是针对连接连接对象, 如果再开一个连接对象, 那么那是默认的提交.
事务是会自动提交的.
需要了解的
安全隐患
读
脏读
一个事务读到了另一个事务未提交的数据
不可重复读
一个事务读到了另一个事务已提交的数据, 造成前后两次查询结果不一致
幻读
一个事务读到了另一个事务 insert 的数据 , 造成前后查询结果不一致 .
写
丢失更新.
隔离级别
读未提交
引发问题: 脏读
读已提交
解决: 脏读 , 引发: 不可重复读
可重复读
解决: 脏读 , 不可重复读 , 未解决: 幻读
可串行化
解决: 脏读, 不可重复读 , 幻读.
MySQL 默认的隔离级别是 可重复读
Oracle 默认的隔离级别是 读已提交
数据库连接池
数据库的连接对象创建工作, 比较消耗性能.
2. 一开始现在内存中开辟一块空间 (集合) , 一开先往池子里面放置 多个连接对象. 后面需要连接的话, 直接从池子里面去. 不要去自己创建连接了. 使用完毕, 要记得归还连接. 确保连接对象能循环利用.
开源连接池
DBCP
导入 jar 文件
不使用配置文件:
- public void testDBCP01(){
- ?
- Connection conn = null;
- PreparedStatement ps = null;
- try {
- //1. 构建数据源对象
- BasicDataSource dataSource = new BasicDataSource();
- // 连的是什么类型的数据库, 访问的是哪个数据库 , 用户名, 密码..
- //jdbc:MySQL://localhost/bank 主协议: 子协议 :// 本地 / 数据库
- dataSource.setDriverClassName("com.mysql.jdbc.Driver");
- dataSource.setUrl("jdbc:mysql://localhost/bank");
- dataSource.setUsername("root");
- dataSource.setPassword("root");
- ?
- //2. 得到连接对象
- conn = dataSource.getConnection();
- String sql = "insert into account values(null , ? , ?)";
- ps = conn.prepareStatement(sql);
- ps.setString(1, "admin");
- ps.setInt(2, 1000);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }finally {
- JDBCUtil.release(conn, ps);
- }
- }
使用配置文件方式:
- Connection conn = null;
- PreparedStatement ps = null;
- try {
- BasicDataSourceFactory factory = new BasicDataSourceFactory();
- Properties properties = new Properties();
- InputStream is = new FileInputStream("src//dbcpconfig.properties");
- properties.load(is);
- DataSource dataSource = factory.createDataSource(properties);
- //2. 得到连接对象
- conn = dataSource.getConnection();
- String sql = "insert into account values(null , ? , ?)";
- ps = conn.prepareStatement(sql);
- ps.setString(1, "liangchaowei");
- ps.setInt(2, 100);
- ps.executeUpdate();
- } catch (Exception e) {
- e.printStackTrace();
- }finally {
- JDBCUtil.release(conn, ps);
- }
- C3P0
拷贝 jar 文件 到 lib 目录
不使用配置文件方式
- Connection conn = null;
- PreparedStatement ps = null;
- try {
- //1. 创建 datasource
- ComboPooledDataSource dataSource = new ComboPooledDataSource();
- //2. 设置连接数据的信息
- dataSource.setDriverClass("com.mysql.jdbc.Driver");
- // 忘记了 ---> 去以前的代码 ---> jdbc 的文档
- dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
- dataSource.setUser("root");
- dataSource.setPassword("root");
- //2. 得到连接对象
- conn = dataSource.getConnection();
- String sql = "insert into account values(null , ? , ?)";
- ps = conn.prepareStatement(sql);
- ps.setString(1, "admi234n");
- ps.setInt(2, 103200);
- ps.executeUpdate();
- } catch (Exception e) {
- e.printStackTrace();
- }finally {
- JDBCUtil.release(conn, ps);
- }
使用配置文件方式
- // 默认会找 xml 中的 default-config 分支.
- ComboPooledDataSource dataSource = new ComboPooledDataSource();
- //2. 设置连接数据的信息
- dataSource.setDriverClass("com.mysql.jdbc.Driver");
- // 忘记了 ---> 去以前的代码 ---> jdbc 的文档
- dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
- dataSource.setUser("root");
- dataSource.setPassword("root");
- //2. 得到连接对象
- conn = dataSource.getConnection();
- String sql = "insert into account values(null , ? , ?)";
- ps = conn.prepareStatement(sql);
- ps.setString(1, "admi234n");
- ps.setInt(2, 103200);
- DBUtils
增删改
- //dbutils 只是帮我们简化了 CRUD 的代码, 但是连接的创建以及获取工作. 不在他的考虑范围
- QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
- ?
- // 增加
- //queryRunner.update("insert into account values (null , ? , ? )", "aa" ,1000);
- // 删除
- //queryRunner.update("delete from account where id = ?", 5);
- // 更新
- //queryRunner.update("update account set money = ? where id = ?", 10000000 , 6);
查询
直接 new 接口的匿名实现类
- QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
- Account account = queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>(){
- @Override
- public Account handle(ResultSet rs) throws SQLException {
- Account account = new Account();
- while(rs.next()){
- String name = rs.getString("name");
- int money = rs.getInt("money");
- account.setName(name);
- account.setMoney(money);
- }
- return account;
- }
- }, 6);
- System.out.println(account.toString());
直接使用框架已经写好的实现类.
查询单个对象
- ```
- QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
- // 查询单个对象
- Account account = queryRunner.query("select * from account where id = ?",
- new BeanHandler(Account.class), 8);
- ?
* 查询多个对象
- QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
- List<Account> list = queryRunner.query("select * from account",
- new BeanListHandler<Account>(Account.class));
- ```
ResultSetHandler 常用的实现类
以下两个是使用频率最高的
BeanHandler, 查询到的单个数据封装成一个对象
BeanListHandler, 查询到的多个数据封装 成一个 List < 对象 >
ArrayHandler, 查询到的单个数据封装成一个数组
ArrayListHandler, 查询到的多个数据封装成一个集合 , 集合里面的元素是数组.
?
?
MapHandler, 查询到的单个数据封装成一个 map
MapListHandler, 查询到的多个数据封装成一个集合 , 集合里面的元素是 map.
- ColumnListHandler
- KeyedHandler
- ScalarHandler
来源: http://www.bubuko.com/infodetail-2987128.html