Durid 连接池
连接池技术预先建立多个数据库连接对象,然后将连接对象保存到连接池中,当客户请求到来时,从池中取出一个连接对象为客户服务,当请求完成后,客户程序调用close0方法,将连接对象放回池中。
优势比较:Durid功能比较全;HikariCP速度比较快
添加Durid依赖
我之前试的是1.1.10,发现导包导不进去,于是用了1.1.9,就可以导入进去了
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
导入能够运行成功,但是配置的时候出现了initial-size不一致的情况,然后新建一个config文件,配置config
出现这个情况的话,我们新建一个config文件,下面再设置一个DuridConfig文件,文件内容如下所示
@Configuration
public class DruidConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource getDataSource(){
return new DruidDataSource();
}
}
最后写完debug一下,正好都是自己设置的属性
使用注解方式完成数据表CRD的操作
Mapper 注解
1、为了把mapper这个DAO交给Spring容器 IOC管理
2、为了不再写mapper映射文件(一个是注解,一个以.xml的形式)
3、添加@Mapper注解的接口生成一个实现类
@Select注解
一般数据表里面写的是这样:例如username或者user_name
1、采用mapUnderscoreToCamelCase:true 驼峰命名的方式来解决
2、@Results / @ResultMap注解的方式
3、数据库字段别名方式
通常采用第一种方式:直接放在yml文件里面配置
动态SQL:#{} 和${}
select * from user where name = ${name};
select * from user where name = #{name};
解析的结果都是相同的;name=hws;
预编译中处理的不一样;占位符和字符串拼接;
#的是是属于占位符的
$的是拼接的,会有漏洞
通常情况下面采用的是#形式
@Insert
不需要返回主键
返回自增主键:@Option
返回非自增主键
@Delete注解
总结流程
1、先写好annotation注解,@Mapper (注意是一个接口 interface)
2、针对不同的操作写不同的方法
使用配置的方式完成update的方式
步骤如下:
1、编写抽象方法 update
int updateUser(SysUser user);
2、配置xml扫描路径 路径下面加的xml才能找到
由于之前在yml里面已经加上了路径
3、编写mapper.xml
Junit单元测试
单元测试用例
1、已知输入和预期的输出,在测试执行前就已知道
2、至少有两个单元测试用例:一个正检验(成功的),一个负检验(有异常之类的)
测试时候出现的问题
Duplicate entry 'hws' for key 'username'
这个问题查了一下,发现是数据库里面已经有这个username 是hws ,于是的话,就换了一个username set进去,然后就ok了
public class DemoApplicationTests {
@Autowired
DataSource dataSource;
@Resource
UserDao userDao;
@Test
public void testInsertUser() {
SysUser sysUser = new SysUser();
sysUser.setUsername("hongweisong");
sysUser.setPassword("123456");
sysUser.setStatus(1);
sysUser.setCreateTime(new Date());
sysUser.setUpdateTime(new Date());
userDao.save(sysUser);
}
}
然后继续完成cURD的编码 创建(Create)、更新(Update)、读取(Retrieve)和删除(Delete)
delete:
public class DemoApplicationTests {
@Autowired
DataSource dataSource;
@Resource
UserDao userDao;
@Test
public void testDeleteUser() {
userDao.deleteUser(46);
}
}
MybatisCodeHelperPro使用:
1、下载破解的ZIP的压缩包
2、直接导入ZIP压缩包
3、onlineActivation里面随便输入
4、验证成功
Spring事务约定
1、声明式事务:@Transactional(推荐)
2、编程式事务
传播行为是方法之间调用事务采取的策略问题
propagation_required是默认的
当有两个方法时,事务A和事务B不知道先调用哪一个,所有有一个传播行为,要知道这个事务是跟着谁在走
事务的特性(ACID)
1、原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么全部不起作用
2、一致性:执行事务前后,数据保持一致
3、隔离性:并发访问数据库的时候,一个用户的事务不被其它事务所干扰,各个并发事务之间的数据库是独立的
4、持久性:一个事务被提交之后,它对数据库中的数据改变是永久的
事务的隔离
会产生 第二类丢失更新的问题
隔离级别
1、未提交读
允许一个事务读取另外一个事务没有提交的数据
并发性能比较好,对数据的一致性没有过高的要求
会产生 脏读
例如A事务还没有提交,B事务就已经读到了A数据的结果(破坏了隔离性)
2、读写提交
一个事务只能读取另外一个数据已经提交的数据,不能读取未提交的数据(可以克服脏读,产生不可重复读场景)
不可重复读
A事务在本次事务中,对自己未操作过的数据,进行了多次的读取,结果出现了不一致或者记录不存在的情况。(破坏了一致性,update和delete)
3、可重复读
幻读:
A事务在本次事务中,对自己未操作过的数据,进行了多次读取,第一次读取时,记录不存在;第二次读取时,记录出现了。(破坏了一致性,insert)
4、串行化
按照一个个的顺序来
性能最差
实际项目中,以第二个 读写提交 为主
**========================================================**
分割一下,事务总的来写一下
1 事务
事务只是一个改变,是一些的操作集合;用专业的术语去解释,就是一个程序的执行单元;事务本身并不包含这四个特性,我们需要通过某些手段,尽可能让这个执行单元满足这四个特性,那么,我们就可以称它是一个事务,或者说是一个正确的,完美的事务。
2 四特性
原子性:满足原子操作单元,对数据的操作,要么全部执行,要么全部不执行。
一致性:事务开始和完成时,数据都必须保持一致。
隔离性:事务之间相互独立,中间状态对外部不可见。
持久性:数据的修改是永久性的,即使系统出现任何故障都能够保持。
3 隔离级别
3.1 并发情况下事务引发的问题
一般情况下,多个单元操作(事务,这里的事务,并不是完美的事务)并发执行,会出现这么几个问题:
脏读:A事务还未提交,B事务就读到了A操作的结果。(破坏了隔离性)
不可重复读:A事务在本次事务中,对自己未操作过数据,进行多次读取,结果出现不一致或记录不存在的情况。(破坏了一致性,重点是update和delete)
幻读:A事务在本次事务中,先读取了一遍数据,发现数据不存在,过了一会,又读取了一遍,发现又有数据了。(破坏了一致性,重点是insert)
3.2 解决(制定标准)
为了权衡『隔离』和『并发』的矛盾,ISO定义了4个事务隔离级别,每个级别隔离程度不同,允许出现的副作用也不同。
未提交读(read-uncommitted):最低级别,基本只保证持久性;会出现脏读,不可重复读,幻读的问题。
已提交读(read-committed):语句级别;会出现不可重复读,幻读的问题。
可重复读(repeatable-read):事务级别;只会出现幻读问题。
串行化(serializable):最高级别,也就是事务与事务完全串行化执行,无并发可言,性能低;但不会出现任何问题。
3.2 实现(InnoDB)
锁机制:阻止其他事务对数据进行操作, 各个隔离级别主要体现在读取数据时加的锁的释放时机。
RU:事务读取时不加锁
RC:事务读取时加行级共享锁(读到才加锁),一旦读完,立刻释放(并不是事务结束)。
RR:事务读取时加行级共享锁,直到事务结束时,才会释放。
SE:事务读取时加表级共享锁,直到事务结束时,才会释放。
其他还有一些细节不同,主要就是这些
MVCC机制:生成一个数据快照,并用这个快照来提供一定级别的一致性读取,也称为多版本数据控制。
实际就是『版本控制』加『读写分离』思想,主要用作于RC和RR级别。
Spring事务实践
在业务层(service)里面放相对应的隔离机制
@Transactional可以作用于类方法上面
1、当作用于类上面时,该类的所有public方法都将具有该类型的事务属性
2、类内部方法调用本类内部的其它方法并不会引起事务行为
3、@Transactional注解应该只被应用到public方法上(由AOP本质决定的)
代码中:
1、在com.hws.demo下面新建一个service目录,里面先写一个interface的接口,名字叫做IUserService ,然后在这个service目录下面建立一个impl文件,文件下面放置UserServiceImpl的class
2、然后的话,在UserServiceImpl里面先写@Service进行SpringIOC的注入,在@Service下面写上@Trans
actional 注解,对应事务,
3、写完@Service和@Transactional这两个注解后,再在UserServiceImpl里面写实现implements,实现IUserService,
4、在IUserService里面写出业务逻辑,比如 int save(SysUser sysuser);
5、在UserServiceImpl里面写上@Override等方法,并且进行注入@Autowired,下面写上 dao的引入 UserDao userDao;
6、在返回return的时候写上userDao下面对应的save方法