SpringBoot集成MyBatis
常见访问数据库方式
1、原始java访问数据库
-
开发流程麻烦
- 注册驱动/加载驱动
Class.forName("com.mysql.jdbc.Driver")
- 建立连接
> Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname","root","root");
- 创建Statement
- 执行SQL语句
- 处理结果集
- 关闭连接,释放资源
2、apache dbutils框架
- 比上一步简单点官网
3、jpa框架
spring-data-jpa:jpa在复杂查询的时候性能不是很好
4、Hiberante
ORM:对象关系映射Object Relational Mapping
企业大都喜欢使用hibernate
5、Mybatis框架
- 互联网行业通常使用mybatis
- 不提供对象和关系模型的直接映射,半ORM
集成步骤
- 添加依赖
<!-- 引入starter-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MySQL的JDBC驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
- 添加配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/tjsdemo?useUnicode=true&characterEncoding=utf-8
username: root
password: zengqiang789
mybatis:
configuration:
# 开启mybatis的sql打印输出,可以不添加
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- 启动类增加mapper扫描
@MapperScan("com.techsel.mapper")
- 书写mapper文件
public interface User2Mapper {
//$ 是字符串拼接:有注入风险,#可以防止注入
@Insert("INSERT INTO user2(name,phone,create_time,age) VALUES(#{name},#{phone},#{createTime},#{age})")
//技巧:保存对象,获取数据库自增id
@Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id")//keyProperty对应java对象的属性;keyColumn数据库字段
int insert(User2 user2);
@Select("SELECT * FROM user2")
@Results({@Result(column = "create_time",property = "createTime")})//下划线转驼峰,column对应数据库字段,property对应java对象属性
List<User2> getAll();
@Select("SELECT * FROM user2 WHERE id = #{id}")
@Results({@Result(column = "create_time",property = "createTime")})
User2 findById(Long id);
@Update("UPDATE user2 SET name=#{name} WHERE id =#{id}")
void update(User2 user);
@Delete("DELETE FROM user2 WHERE id =#{userId}") //userId对应参数中的Long userId
void delete(Long userId);
}
- 实体类
public class User2 {
Integer id;
String name;
String phone;
Integer age;
Date createTime;
public int getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
- 在使用的地方注入mapper
@Autowired
private User2Mapper userMapper2;
隔离级别和传播行为
- 讲解场景的隔离级别
- Serializable: 最严格,串行处理,消耗资源大
- Repeatable Read:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据
- Read Committed:大多数主流数据库的默认事务等级
- Read Uncommitted:保证了读取过程中不会读取到非法数据。
- 讲解常见的传播行为
- PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务,最常见的选择。
- PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起, 两个事务之间没有关系,一个异常,一个提交,不会同时回滚
- PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常
简单案例
1、service逻辑引入事务 @Transantional(propagation=Propagation.REQUIRED)
2、service代码
@Override
@Transactional
public int addAccount() {
User user = new User();
user.setAge(9);
user.setCreateTime(new Date());
user.setName("事务测试");
user.setPhone("000121212");
userMapper.insert(user);
int a = 1/0;
return user.getId();
}
Transantional相关属性
属性 | 类型 | 描述 |
---|---|---|
value | String | 可选的限定描述符,指定使用的事务管理器 |
propagation | enum: Propagation | 可选的事务传播行为设置 |
isolation | enum: Isolation | 可选的事务隔离级别设置 |
readOnly | boolean | 读写或只读事务,默认读写 |
timeout | int (in seconds granularity) | 事务超时时间设置 |
rollbackFor | Class对象数组,必须继承自Throwable | 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组,必须继承自Throwable | 导致事务回滚的异常类名字数组 |
noRollbackFor | Class对象数组,必须继承自Throwable | 不会导致事务回滚的异常类数组 |
noRollbackForClassName | 类名数组,必须继承自Throwable | 不会导致事务回滚的异常类名字数组 |
网友评论