1.事务
开启事务:start transaction;
回滚事务:rollback;
提交事务: commit;
关闭自动提交事务:setAutoCommit(false);
1.1事务的特性ACID【面试】
1.原子性【A】:事务包含的逻辑不可分割
一致性【C】:事务执行前后,数据完整性
隔离性【I】 :事务执行期间不受其他事务影响
持久性【D】:事务执行成功,则数据永久保存到磁盘上;
1.1.2.事务的安全隐患:
不考虑隔离级别设置:
【读】:
1.脏读:>>>一个事务读到另外一个事务还未提交的数据;
2.不可重复读:>>>一个事务读到了另外一个事务提交的数据,造成两次查询结果不一致;>>>解决:重复读:repeatable read;【默认】
3.幻读:一个事务读到另外一个事务已提交插入的数据,导致多次查询结果不一致。>>>>解决:Serializable【可串行化】最高级别
四个隔离级别的效率从高到低排列:
读未提交>读已提交>可重复读>可串行化
拦截程度相反
【写】:丢失更新
>>>解决:1.悲观锁;
======== 2.乐观锁
【mysql默认隔离级别:可重复读】
【oracle默认隔离级别:读已提交】
1.1.3在代码中使用事务的步骤
Connection conn = JDBCUtil.getConn();
conn.setAutoCommit(false);//关闭事务的自动提交
.....
conn.commit();//提交
conn.roolback();//回滚
2.数据库连接池
2.1DBCP连接池【了解】
dbcp创建dataSource方式:
BasicDataSource dataSource = new BasicDataSource();
2.1.1使用代码方式连接【了解】
将数据插入到bank下的account表中
public class demo1 {
@Test
public void dbcp(){
Connection conn = null;
PreparedStatement ps = null;
try {
//1.构建数据源对象
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost/bank");
dataSource.setUsername("root");
dataSource.setPassword("123456");
//2.获得连接对象
conn = dataSource.getConnection();
String sql = "insert into account values(null,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "admin");
ps.setInt(2, 20000);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps);
}
}
}
2.1.2使用配置文件方式
2.2 c3p0连接池【掌握】
c3p0创建dataSource连接方式:
ComboPooledDataSource dataSource = new ComboPooledDataSource();
2.2.1代码连接【了解】
public class demo1 {
@Test
public void c3p0() throws PropertyVetoException{
Connection conn = null;
PreparedStatement ps = null;
try {
//1.创建dataSource
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2.设置连接数据信息
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
dataSource.setUser("root");
dataSource.setPassword("123456");
conn = dataSource.getConnection();
String sql = "insert into account values(null,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "aaa");
ps.setInt(2, 12000);
ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps);
}
}
}
2.2.2c3p0配置文件连接方式【★掌握】
c3p0-config.xml的源文件
<c3p0-config>
<default-config>
<property name="automaticTestTable">con_test</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</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>
<user-overrides user="test-user">
<property name="maxPoolSize">10</property>
<property name="minPoolSize">1</property>
<property name="maxStatements">0</property>
</user-overrides>
</default-config>
<!-- This app is massive! -->
<named-config name="intergalactoApp">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property>
<!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
<!-- he's important, but there's only one of him -->
<user-overrides user="master-of-the-universe">
<property name="acquireIncrement">1</property>
<property name="initialPoolSize">1</property>
<property name="minPoolSize">1</property>
<property name="maxPoolSize">5</property>
<property name="maxStatementsPerConnection">50</property>
</user-overrides>
</named-config>
</c3p0-config>
所以我们在定义c3p0配置文件时必须也使用c3p0-config.xml这个名字
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost/bank</property>
<property name="user">root</property>
<property name="password">123456</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>
</c3p0-config>
c3p0_demo2.java
public class c3p0_demo2 {
@Test
public void test(){
Connection conn = null;
PreparedStatement ps = null;
try {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//获得连接对象
conn = dataSource.getConnection();
String sql = "insert into account values(null,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "c3p0");
ps.setInt(2, 18000);
ps.executeUpdate();//执行
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps);//释放
}
}
}
运行后数据库情况
这里就把数据插进来了。
【特别注意】xml文件的命名一定是:c3p0-config.xml,否则就会执行失败
3.DBUtiles
QueryRunner
//1.c3p0创建连接
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2.dbUtil只是简化CRUD的代码,但是不可以创建连接
QueryRunner run = new QueryRunner(dataSource);
两个常用的方法:
1.queryRunner.update();//增删改
2.queryRunner.query();//查询
3.1DBUtiles里的增删改
dbUtil只是简化CRUD的代码,但是不可以创建连接
public class Tset {
@Test
public void testInsert() throws SQLException{
//1.c3p0创建连接
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2.dbUtil只是简化CRUD的代码,但是不可以创建连接
QueryRunner run = new QueryRunner(dataSource);
String sql = "insert into account values(null,?,?)";
//3.增加
run.update(sql, "dbutil",230000);
//4.删除
run.update("delete from account where id = ?", 8);
//5.更新
run.update("update account set money=? where id=?", 20000,4);
}
}
3.2DBUtiles通用的增删改方法
通过元数据获取有几个?(即占位符)
ParameterMetaData metaData = ps.getParameterMetaData();
int count = metaData.getParameterCount();
public void test(){
update("insert into account values(null,?,?)", "common",100000);
}
public class CommonUtil {
public void update(String sql,Object...args){
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCUtil.getConn();
ps = conn.prepareStatement(sql);
ParameterMetaData metaData = ps.getParameterMetaData();//获取元数据
int count = metaData.getParameterCount();//获取个数,这里获取?的个数
for (int i = 0; i < count; i++) {
ps.setObject(i+1, args[i]);
}
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps);
}
}
}
3.3DBUtiles里的查询
这里用到泛型,现在Domain层建立一个Account类:
生成set,get方法,重写String
private String name;
private int money;
(一)代码实现
1.查询单条数据
new BeanHandler<‘T’>(class文件);
public class Select {
@Test
public void selectDemo() throws SQLException{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
QueryRunner runner = new QueryRunner(dataSource);
//查询单条数据
Account account = runner.query("select * from account where id=?",
new BeanHandler<Account>(Account.class), 9);
System.out.println(account);
}
}
Account [name=dbutil, money=230000]
2.查询多条数据
new BeanListHandler<‘T’>(class);
public class Select {
@Test
public void selectDemo() throws SQLException{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
QueryRunner runner = new QueryRunner(dataSource);
//查询单条数据
List<Account> list= runner.query("select * from account",
new BeanListHandler<Account>(Account.class));
System.out.println(list);
}
}
[Account [name=张三, money=23000], Account [name=李四, money=25000], Account [name=admin, money=20000], Account [name=aaa, money=20000], Account [name=c3p0, money=18000], Account [name=dbutil, money=230000], Account [name=dbutil, money=230000], Account [name=dbutil, money=230000], Account [name=dbutil, money=230000]]