create table account (
id int primary key auto_increment,
name varchar(20),
money double
);
insert into account values(null,'a',1000),(null,'b',1000);java
1、事务
事务的概念:事务是指逻辑上的一组操做,这组操做要么同时完成要么同时不完成.
事务的管理:默认状况下,数据库会自动管理事务,管理的方式是一条语句就独占一个事务.
若是须要本身控制事务也能够经过以下命令开启/提交/回滚事务
start transaction;
commit;
rollback;
JDBC中管理事务:
conn.setAutoCommit(false);
conn.commit();
conn.rollback();
SavePoint sp = conn.setSavePoint();
conn.rollback(sp);
事务的四大特性:一个事务具备的最基本的特性,一个设计良好的数据库能够帮咱们保证事务具备这四大特性(ACID)
原子性:原子性是指事务是一个不可分割的工做单位,事务中的操做要么都发生,要么都不发生。
一致性:若是事务执行以前数据库是一个完整性的状态,那么事务结束后,不管事务是否执行成功,数据库仍然是一个完整性状态.
数据库的完整性状态:当一个数据库中的全部的数据都符合数据库中所定义的全部的约束,此时能够称数据库是一个完整性状态.
隔离性:事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即便数据库发生故障也不该该对其有任何影响。
隔离性:
将数据库设计成单线程的数据库,能够防止全部的线程安全问题,天然就保证了隔离性.可是若是数据库设计成这样,那么效率就会极其低下.
数据库中的锁机制:
共享锁:在非Serializable隔离级别作查询不加任何锁,而在Serializable隔离级别下作的查询加共享锁,
共享锁的特色:共享锁和共享锁能够共存,可是共享锁和排他锁不能共存
排他锁:在全部隔离级别下进行增删改的操做都会加排他锁,
排他锁的特色:和任意其余锁都不能共存
若是是两个线程并发修改,必定会互相捣乱,这时必须利用锁机制防止多个线程的并发修改
若是两个线程并发查询,没有线程安全问题
若是两个线程一个修改,一个查询......
四大隔离级别:
Read uncommitted -- 不防止任何隔离性问题,具备脏读/不可重复度/虚读(幻读)问题
Read committed -- 能够防止脏读问题,可是不能防止不可重复度/虚读(幻读)问题
Repeatable read -- 能够防止脏读/不可重复读问题,可是不能防止虚读(幻读)问题
Serializable -- 数据库被设计为单线程数据库,能够防止上述全部问题
从安全性上考虑: Serializable>Repeatable read>read committed>read uncommitted
从效率上考虑: read uncommitted>read committed>Repeatable read>Serializable
真正使用数据的时候,根据本身使用数据库的需求,综合分析对安全性和对效率的要求,选择一个隔离级别使数据库运行在这个隔离级别上.
mysql 默认下就是Repeatable read隔离级别
oracle 默认下就是read committed个隔离级别
查询当前数据库的隔离级别:select @@tx_isolation;
设置隔离级别:set [global/session] transaction isolation level xxxx;其中若是不写默认是session指的是修改当前客户端和数据库交互时的隔离级别,而若是使用golbal,则修改的是数据库的默认隔离级别
脏读:一个事务读取到另外一个事务未提交的数据
a 1000
b 1000
----------
a:
start transaction;
update account set money=money-100 where name=a;
update account set money=money+100 where name=b;
----------
b:
start transaction;
select * from account;
a : 900
b : 1100
----------
a:
rollback;
----------
b:
start transaction;
select* from account;
a: 1000
b: 1000
不可重复读:在一个事务内读取表中的某一行数据,屡次读取结果不一样 --- 行级别的问题
a: 1000 1000 1000
b: 银行职员
---------
b:start transaction;
select 活期存款 from account where name='a'; ---- 活期存款:1000
select 按期存款 from account where name='a'; ---- 按期存款:1000
select 固定资产 from account where name='a'; ---- 固定资产:1000
-------
a:
start transaction;
update accounset set 活期=活期-1000 where name='a';
commit;
-------
select 活期+按期+固定 from account where name='a'; --- 总资产:2000
commit;
----------
虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,致使先后读取不一致 --- 表级别的问题
a: 1000
b: 1000
d: 银行业务人员
-----------
d:
start transaction;
select sum(money) from account; --- 2000 元
select count(name) from account; --- 2 个
------
c:
start transaction;
insert into account values(c,4000);
commit;
------
select sum(money)/count(name) from account; --- 平均:2000元/个
commit;
------------
更新丢失问题:
两个线程基于同一个查询结果进行修改,后修改的人会将先修改人的修改覆盖掉.
悲观锁:悲观锁悲观的认为每一次操做都会形成更新丢失问题,在每次查询时就加上排他锁
乐观锁:乐观锁会乐观的认为每次查询都不会形成更新丢失.利用一个版本字段进行控制
查询很是多,修改很是少,使用乐观锁
修改很是多,查询很是少,使用悲观锁mysql
=================================================================================
2、数据库链接池
手写链接池:
改造conn的close方法
继承
装饰
!动态代理
web
开源数据源:
DBCP:
方式1: sql
BasicDataSource source = new BasicDataSource(); source.setDriverClassName("com.mysql.jdbc.Driver"); source.setUrl("jdbc:mysql:///day11"); source.setUsername("root"); source.setPassword("root");
方式2:数据库
Properties prop = new Properties(); prop.load(new FileReader("dbcp.properties")); BasicDataSourceFactory factory = new BasicDataSourceFactory(); DataSource source = factory.createDataSource(prop);
配置文件中:tomcat
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///day11 username=root password=root
#<!-- 初始化链接 -->
initialSize=10安全
#最大链接数量
maxActive=50session
#<!-- 最大空闲链接 -->
maxIdle=20并发
#<!-- 最小空闲链接 -->
minIdle=5oracle
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
C3P0数据源:
方式1:
ComboPooledDataSource source = new ComboPooledDataSource(); source.setDriverClass("com.mysql.jdbc.Driver"); source.setJdbcUrl("jdbc:mysql:///day11"); source.setUser("root"); source.setPassword("root");
方式2:
ComboPooledDataSource source = new ComboPooledDataSource();
在类加载目录下名称为c3p0-config.xml的配置文件中配置:
<c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///day11</property> <property name="user">root</property> <property name="password">root</property> </default-config> </c3p0-config>
tomcat内置的数据源(DBCP):
~1.如何为tomcat配置数据源
~tomcat/conf/context.xml文件中配置<Context>配置在这个位置的信息将会被全部的web应用所共享
~tomcat/conf/[engin]/[Host]/context.xml文件中能够配置<Context>标签,这里配置的信息将会被这台虚拟主机中的全部web应用所共享
~tomcat/conf/server.xml文件中的<Host>标签中配置<Context>标签,这是web应用的第一种配置方式,在这个标签中配置的信息将只对当前web应用起做用
~tomcat/conf/[engin]/[Host]/本身建立一个.xml文件,在这个文件中使用<Context>标签配置一个web应用,这是web应用第二种配置方式,在这个<Context>标签中配置的信息将只会对当前web应用起做用
~web应用还有第三种配置方式:将web应用直接放置到虚拟主机管理的目录.此时能够在web应用的META-INF文件夹下建立一个context.xml文件,在其中能够写<Context>标签进行配置,这种配置信息将只会对当前web应用起做用
<Resource name="mySource" auth="Container" type="javax.sql.DataSource" username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql:///day11" maxActive="8" maxIdle="4"/>
~2.若是在程序中获取这个数据源
想要访问jndi就必须在Servlet中才能执行下列代码:
Context initCtx = new InitialContext(); Context jndi = (Context) initCtx.lookup("java:comp/env"); DataSource source = jndi.lookUp("mySource");