数据库连接池(数据源)
首先创建一批连接,放在容器中,在需要连接的时候,就从中获取一个连接,用完之后,再还回池中
数据库连接池的优点
传统的数jdbc据库查询,创建连接对象,查询完毕关闭连接对象,会耗时,没有复用,效率很低
使用连接池,可以实现连接的复用,减少连接创建关闭次数,提高效率
C3P0连接池的三种使用方式
- 下载地址https://sourceforge.net/projects/c3p0/?source=navbar
- 在项目中添加C3P0连接池依赖,这两个包都要导入,不然会报错
方式1:直接在代码中使用
private static void loginPBc3p0() { Connection connection=null; PreparedStatement preparedStatement=null; ResultSet resultSet=null; ComboPooledDataSource comboPooledDataSource=new ComboPooledDataSource(); try { comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver"); //localhost:3306可以省略 comboPooledDataSource.setJdbcUrl("jdbc:mysql:///数据库名?characterEncoding=UTF-8"); comboPooledDataSource.setUser("数据库登录名"); comboPooledDataSource.setPassword("数据库登录密码"); connection=comboPooledDataSource.getConnection(); String sql="select * from people"; preparedStatement=connection.prepareStatement(sql); resultSet=preparedStatement.executeQuery(); while(resultSet.next()) { String name_sql=resultSet.getString("name"); System.out.println(name_sql); } } catch (Exception e) { e.printStackTrace(); }finally { JdbcUtil.close(resultSet, preparedStatement, connection); } }
方式2:创建xml文件放在项目根目录(推荐用xml文件的形式)
- 创建一个c3p0-config.xml文件,这个文件名是固定的,放在src目录下
点击菜单栏File,选择other,创建c3p0-config.xml
文件内容
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.cj.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///数据库名?characterEncoding=UTF-8</property> <property name="user">数据库登录名</property> <property name="password">数据库登录密码</property> </default-config> </c3p0-config>
java类中的,这几行注释就可以了
// comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
// //localhost:3306可以省略
// comboPooledDataSource.setJdbcUrl("jdbc:mysql:///sujianda?characterEncoding=UTF-8");
// comboPooledDataSource.setUser("root");
// comboPooledDataSource.setPassword("wojiaosujianda99");
方式3:创建properties文件
在src目录下创建名字为c3p0.properties的文件
点击菜单栏File,选择other,创建c3p0.properties
文件内容
c3p0.driverClass=com.mysql.cj.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///数据库名?characterEncoding=UTF-8 c3p0.user=数据库登录名 c3p0.password=数据库登录密码
同样的 也要把java文件中的那4行注释掉
事务
把一堆SQL语句绑定在一起执行,只有两种情况,要么全部执行成功,要么全部执行失败
它有4个特性
原子性:事务中的所有操作是一个整体,不可以再分割,要么全部执行成功,要么全部执行失败
一致性:事务前后的业务数据保持一致
隔离性:多个事务之间具有隔离性,不会互相访问,一个事务不能访问另一个事务正在执行的状态,只有隔离性等级高可以完全隔离开。
永久性:如果事务中的SQL语句全部执行成功,事务就会提交,此时结果就会保存到数据库
MySQL事务操作
开启事务:start transaction;
结束事务:提交(commit;)或回滚(rollback;)
假如有这样一张表
通过事务,我让张飞给赵云转账100;
执行SQL语句:
start transaction;
update people set salary=salary-100 where name='张飞';
commit; //只有commit之后,数据库里的数据才会最终改变
事务对并发读问题
脏读:读到另一个事务的未提交的更新数据;
不可重复读:一个事务在读取数据的时候,两次查询结果不一致,因为另一个事务对该记录做了修改
幻读或者叫虚读:对同一张表的两次查询不一致,因为另一个事务插入里一条记录,针对插入或删除操作
MySql默认不允许出现脏读和不可重复读
事务的隔离级别
事务隔离级别,就是为了解决上面几种问题而诞生的。为什么要有事务隔离级别,因为事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡。所以设立了几种事务隔离级别,以便让不同的项目可以根据自己项目的并发情况选择合适的事务隔离级别,对于在事务隔离级别之外会产生的并发问题,在代码中做补偿。一般不需要手动改
1、READ_UNCOMMITTED
读未提交,可能出现任何事务并发问题(脏读,不可重复度,幻读),性能最好,但是不用;
2、READ_COMMITED(Oracle数据库默认的)
读已提交,即能够读到那些已经提交的数据,防止脏读,没有处理不可重复读和幻读;性能次之;
3、REPEATABLE_READ(MySql默认)
可重复读,防止脏读和不可重复读,没有处理幻读,性能再次之;
4、SERLALIZABLE
串行化,不会出现任何并发读问题,性能最差
5、DEFAULT
默认隔离级别,每种数据库支持的事务隔离级别不一样,如果Spring配置事务时将isolation设置为这个值的话,那么将使用底层数据库的默认事务隔离级别。顺便说一句,如果使用的MySQL,可以使用"select @@tx_isolation"来查看默认的事务隔离级别
网上专门有图用表格的形式列出了事务隔离级别解决的并发问题:
再必须强调一遍,不是事务隔离级别设置得越高越好,事务隔离级别设置得越高,意味着势必要花手段去加锁用以保证事务的正确性,那么效率就要降低,因此实际开发中往往要在效率和并发正确性之间做一个取舍,一般情况下会设置为READ_COMMITED,此时避免了脏读,并发性也还不错,之后再通过一些别的手段去解决不可重复读和幻读的问题就好了。