在Spring Boot中通过在pom.xml文件中的dependency来引入data-jpa的完整依赖,实现dao层的快速实现。
数据库类型: MySQL
应用框架: Spring Boot 2.1.4.RELEASE
JDK: 8
基于data-jpa方式的依赖引入如下:
org.springframework.boot
spring-boot-starter-data-jpa
在代码中使用了事务进行管理,但是在异常发生之时,异常发生点之前的数据库操作还是被写入到了数据库,换句话说,数据操作的事务管理并未正确生效。
核心代码如下:
import java.util.Date;
import java.util.List;
import org.bistu.course.dao.entity.ProductEntity;
import org.bistu.course.dao.entity.SaleRecord;
import org.bistu.course.dao.repository.ProductRepository;
import org.bistu.course.dao.repository.SaleRepository;
import org.bistu.course.helper.ProductType;
import org.bistu.course.helper.SaleType;
import org.bistu.course.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
@Service
@Slf4j
public class ProductServiceImpl implements ProductService {
@Autowired
private SaleRepository saleRepo;
@Autowired
private ProductRepository productRepo;
@Transactional
@Override
public List testTransaction() {
ProductEntity entity = new ProductEntity();
entity.setName("Product12");
entity.setCountNum(12);
entity.setCreatedTime(new Date());
entity.setUpdatedTime(new Date());
entity.setProdcutType(ProductType.Device);
entity.setProductTypeDesc(ProductType.Device);
entity = this.productRepo.save(entity);
log.info("Save Product:{}", entity);
if (2 == 2)
throw new RuntimeException("whatever it is");
SaleRecord saleRecord = new SaleRecord();
saleRecord.setCost(123.0f);
saleRecord.setCount(123);
saleRecord.setProductId(112l);
saleRecord.setCreatedTime(new Date());
saleRecord.setSaleType(SaleType.Partner);
saleRecord.setUserId(12l);
this.saleRepo.save(saleRecord);
log.info("Save SaleRecord:{}", saleRecord);
List products = this.productRepo.findAll();
return products;
}
}
在代码中进行了两个写入操作,在第一个写入操作之后,跑出异常,第二个写入操作,将无法实现写入操作。通过事务管理的方式实现回滚操作。
但是在实际执行中,却是Product的数据被写入了数据库。
在使用@Transactional之时一定要注意,其中存在两个这样的注解:
javax.persistence.Transactional
其中定义了value, dontRollbackOn, rollbackOn三个属性信息
org.springframework.transaction.annotation.Transactional
其中定义了多个属性信息: readOnly,timeout,rollbackFor,noRollbackForClassName,
noRollbackFor,rollbackForClassName。
而在代码中实际使用的是Spring Framework提供的@Transactional的实现,大家需要格外注意这个事项。
关于Spring框架提供的@Transactional的使用,大家可以参阅笔者之前的文章。
MyISAM:默认表类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法.不是事务安全的,而且不支持外键,如果执行大量的select,insert MyISAM比较适合。
InnoDB:支持事务安全的引擎,支持外键、行锁、事务是他的最大特点。Innodb最初是由innobase Oy公司开发,2006年5月由oracle公司并购,目前innodb采用双授权,一个是GPL授权,一个是商业授权。如果有大量的update和insert,建议使用InnoDB,特别是针对多个并发和QPS较高的情况。
myisam只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。也可以通过lock table命令来锁表,这样操作主要是可以模仿事务,但是消耗非常大,一般只在实验演示中使用。
MyISAM不是事务安全的,而且也不支持外键。如果事物回滚将造成不完全回滚,不具有原子性。
InnoDB:Innodb支持事务和行级锁,是innodb的最大特色。事务的ACID属性:atomicity, consistent, isolation, duration.
在application.properties中的设置:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
此时默认使用的MySQL存储引擎为MyISAM.
根据上述说明,其中并不支持事务操作,所以其是无法实现事务管理的。
如何来设置InnoDB?
在application.properties
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
如何来判定当前表的存储类型?
mysql -u root -p
use database_name;
show create table table_name;
MyISAM的表创建语句信息:
InnoDB的表创建语句信息:
通过将数据库表的存储引擎更新为InnoDB,让其支持事务,实现了数据访问层的回滚操作。
在验证过程中一共碰到了两个问题: