事物:
1开启事务
2事务滚点
3提交事务
代码体现:
/*
create database day19;
create table account(
id int primary key ,
name varchar(100),
money float
)character set utf8 collate utf8_general_ci;
insert into account values(1,'aaa',1000);
insert into account values(2,'bbb',1000);
insert into account values(3,'ccc',1000);
*/
public class TransactionDemo1 {
@Test
public void testTransaction(){
Connection conn=null;
PreparedStatement stmt=null;
Savepoint sp=null;
try{
conn=JdbcUtil.getConnection();
conn.setAutoCommit(false);//开启事物
stmt=conn.prepareStatement("update account set money=money-100 where name='aaa'");
stmt.executeUpdate();
stmt=conn.prepareStatement("update account set money=money+100 where name='bbb'");
stmt.executeUpdate();
sp=conn.setSavepoint();//回滚点
stmt=conn.prepareStatement("update account set money=money-100 where name='bbb'");
stmt.executeUpdate();
int i=1/0;
stmt=conn.prepareStatement("update account set money=money+100 where name='ccc'");
stmt.executeUpdate();
conn.commit();
}catch(Exception e){
e.printStackTrace();
try {
if(conn!=null){
conn.rollback(sp);
}else{
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
JdbcUtil.release(null, stmt, conn);
}
}
}mysql
模拟链接池:
public class SimpleConnectionPool {
private static LinkedList<Connection> pool=new LinkedList<Connection>();
static{
//链接池初始化
try {
for(int i=0;i<10;i++){
pool.add(JdbcUtil.getConnection());
}
} catch (Exception e) {
throw new ExceptionInInitializerError("链接池初始化失败");
}
}
public synchronized static Connection getConnection(){
if(pool.size()>0){
return pool.removeFirst();
}else{
throw new RuntimeException("服务器正忙");
}
}
public static void release(Connection conn){
pool.addLast(conn);
面试
事物的隔离级别:
一、事务的特性:(面试题)
原子性:处于同一个事务中的多条语句,要么全都成功,要么全都不成成功。
一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态。好比转帐:转帐前a+b=2000,转帐后a+b=2000
隔离性:多线程并发时,一个事务不能被其余事务所干扰。
持久性:数据应该被永久性的保存起来。(硬盘,而不是内存)
ACID
二、事务的隔离性专题
若是不考虑事务的隔离性,会致使如下不正确的问题:
a、脏读:指一个事务读到了另一个事务中未提交的数据
b、不可重复读:指一个事务读到了另一个事务update后(事务提交了)的数据
c、虚读:指一个事务读到了另一个事务insert的数据sql
三、演示操做:
3.1数据库控制隔离级别相关的语句(必须用在事务之中):数据库
数据库有四个隔离级别:
READ UNCOMMITTED:脏读、不可重复读、虚读都有可能发生。
READ COMMITTED:防止脏读发生;不可重复读、虚读都有可能发生。
REPEATABLE READ:(MySQL默认级别)防止脏读、不可重复读;虚读有可能发生。
SERIALIZABLE:防止脏读、不可重复读、虚读的发生安全
特色:从上到下,隔离级别越高,数据越安全,可是效率越低服务器
select @@tx_isolation; 查看当前数据库的隔离级别
set transaction isolation level 四个级别之一;更改当前事务的隔离级别多线程
代码体现:
public class TxIsolationDemo {
@Test
public void test(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);//只能防止脏读的发生.注意,必定要放在开始事务以前
conn.setAutoCommit(false);//开启事务
//查询aaa帐户的余额
stmt = conn.prepareStatement("select * from account where name='aaa'");
rs = stmt.executeQuery();
if(rs.next()){
System.out.println("第一次查询:"+rs.getString("money"));
}
//在查询aaa帐户的余额
stmt = conn.prepareStatement("select * from account where name='aaa'");
rs = stmt.executeQuery();
if(rs.next()){
System.out.println("第二次查询:"+rs.getString("money"));
}
conn.commit();
}catch(Exception e){
if(conn!=null){
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}finally{
JdbcUtil.release(rs, stmt, conn);
}
}
}并发
基于接口的动态代理:
静态代理:
代码体现:
接口:app
public interface Human {
void sing(float money);
void dance(float money);
}ide
歌手类:
public class SpringBrother implements Human {
public void sing(float money){
System.out.println("开始唱歌"+money);
}
public void dance(float money){
System.out.println("开始跳舞"+money);
}
}
代理人类:
public class ProxyMan {
private SpringBrother sb=new SpringBrother();
public void sing(float money){
if(money>1000){
money=money/2;
sb.sing(money);
}else{
throw new RuntimeException("出场费不得低于1000");
}
}
public void dance(float money){
if(money>1000){
money=money/2;
sb.dance(money);
}else{
throw new RuntimeException("出场费不得低于1000");
}
}
}
客户类:
public class Client {
private static ProxyMan pm=new ProxyMan();
public static void main(String[] args) {
pm.sing(2000);
pm.dance(2000);
}
}
动态代理:(在内存中生成代理类或者代理类的实例)
1:基于接口的动态代理
public class Client {
public static void main(String[] args) {
final Human h=new SpringBrother();//原有对象
Human hMan=(Human)Proxy.newProxyInstance(h.getClass().getClassLoader(), h.getClass().getInterfaces(), new InvocationHandler() {
//匿名内部类实现接口
//全部调用被代理类对象的方法,都会通过该方法
/**
* Object proxy:代理对象自己的引用
* Method method:当前调用的是哪一个方法
* Object[] args:当前调用的方法用到的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String metnodName=method.getName();
if("sing".equals(metnodName)){
float money=(Float) args[0];
if(money>1000){
money=money/2;
h.sing(money);
}else{
throw new RuntimeException("出场费不得低于1000");
}
}else if("dance".equals(metnodName)){
float money=(Float) args[0];
if(money>1000){
money=money/2;
h.dance(money);
}else{
throw new RuntimeException("出场费不得低于1000");
}
}
return null;
}
});
hMan.sing(10000);
hMan.dance(10000);
}
}
2:基于子类的动态代理:
person类:
public class Person {
public void m1(){
System.out.println("方法m1执行了");
}
}
贷代码体现:
public class PersonDemo {
public static void main(String[] args) {
final Person p=new Person();
Person pp=(Person)Enhancer.create(p.getClass(), new MethodInterceptor(){
public Object intercept(Object proxy, Method method, Object[] arg2,
MethodProxy arg3) throws Throwable {
long time=System.nanoTime();
Object obj=method.invoke(p, arg2);
System.out.println(method.getName()+"运行了"+(System.nanoTime()-time));
return obj;
}
});
pp.m1();
}
}
动态代理实现close方法的改变:
public class MyDataSource3 implements DataSource {
private static List<Connection> pool = new ArrayList<Connection>();
static {
try {
for (int i = 0; i < 10; i++) {
Connection conn = JdbcUtil.getConnection();
pool.add(conn);
}
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
// 获取连接
public synchronized Connection getConnection() throws SQLException {
if (pool.size() > 0) {
final Connection conn = pool.remove(0);// com.mysql.jdbc.COnnection
Connection proxyConn = (Connection) Proxy.newProxyInstance(conn
.getClass().getClassLoader(), conn.getClass()
.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//若是用户调用的是close方法,把连接还回池中。其余方法,用原有对象的
if("close".equals(method.getName())){
System.out.println("你调用的是close,还回池中");
return pool.add(conn);
}else{
System.out.println("调用的其余方法,什么都没作");
return method.invoke(conn, args);
}
}
});
return proxyConn;
} else {
throw new RuntimeException("服务器真忙");
}
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Connection getConnection(String username, String password)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
}