Mybatis与Jpa的区别和性能对⽐总结
前⾔
这⼏天听朋友说JPA很好⽤,根本不⽤写sql。我在想⼀个程序员不写sql还能叫程序员?⽽且越⾼级的⼯具封装越多的⼯具,可拓展性和效率就⾮常的低,况且我本⾝⾮常不喜欢过于封装的东西,平时喜欢⼿写sql,所以⼀直都是⽤mybatis去写业务。然后发现jpa的saveAll()批量插⼊批量更新速度太慢了,导致⼀些⽤excel导⼊的⼀些东西⾮常慢,弄得原本同步可以解决的事情每次导⼊都要开启⼀个异步,个⼈感觉这种做法⾮常不好。因为异步其实就是对当前的业务不影响去另外的时间段去做,例如跑定时任务,异步更新增量信息等。代码⾥⾮常多异步包异步的东西,也就是说excel导⼊是异步,然后jpa⼜慢,异步⾥⾯⼜包涵异步,整个链路⾮常长,可能发⽣问题都要排查半天。
安装jpa和mybatis
<dependency>
<groupId&batis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
这些东西只要引⼊⼀个springboot的xml作为⽗类就⾏
创建⼀个类
@Data
public class TestMybatis {
private Long id;
/**
* 域账号
*/
private String userId;
/**
* 主度量
*/
private String mainMetric;
/**
* ⼦度量
*/
private String subMetric;
/**
* 度量条⽬
*/
private String metricItem;
}
@SuppressWarnings("serial")
@javax.persistence.Entity
@javax.persistence.Table(name = "test")
@lombok.Data
public class TestJpa {
@javax.persistence.Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 域账号
*/
private String userId;
/**
* 主度量
*/
private String mainMetric;
/**
* ⼦度量
*/
private String subMetric;
/**
* 度量条⽬
*/
private String metricItem;
}
/
**
* @author Kakki
* @version 1.0
* @create 2021-06-17 17:39
* 这个是⽤来Jpa跟Mapper差不多
*/
@Repository
public interface TestRee extends JpaRepository<TestRe, String> {
}
这是mybatis的xml
<insert id="insertList">
insert into test(user_id,main_metric, sub_metric, metric_item) values
<foreach collection="param" item="item" separator=",">
(#{item.userId}, #{item.mainMetric}, #{item.subMetric}, #{icItem})
</foreach>
</insert>
下⾯我们来看看速度
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ColaDemoApplication.class})
class ColaDemoApplicationTests {
@Autowired
private TestRee testRee;
@Autowired
private MetricMapper metricMapper;
@Test
void contextLoads() {
List<TestJpa> jpaList = new ArrayList<>(1000);
List<lademo.gatewayimpl.database.dataobject.TestMybatis> mybatisList = new ArrayList<>(1000);
for (int i = 0; i < 1000; i++) {
TestJpa testJpa = new TestJpa();
testJpa.setMainMetric(String.format("mainMetric%d", i));
testJpa.setSubMetric(String.format("subMetric%d", i));
testJpa.setUserId(String.format("userId%d", i));
testJpa.setMetricItem(String.format("metricItem%d", i));
jpaList.add(testRe);
lademo.gatewayimpl.database.dataobject.TestMybatis testMybatis = new lademo.gatewayimpl.database.dataobject.TestMybatis(); testMybatis.setMainMetric(String.format("mainMetric%d", i));
testMybatis.setSubMetric(String.format("subMetric%d", i));
testMybatis.setUserId(String.format("userId%d", i));
testMybatis.setMetricItem(String.format("metricItem%d", i));
mybatisList.add(testR);
springboot其实就是spring}
StopWatch jpa = new StopWatch();
jpa.start();
testRee.saveAll(jpaList);
jpa.stop();
log.info("[jpa]{}ms", TotalTimeMillis());
StopWatch m = new StopWatch();
m.start();
metricMapper.insertList(mybatisList);
m.stop();
log.info("[m]{}ms", m.getTotalTimeMillis());
}
}
22:35:10.708 [main] INFO ColaDemoApplicationTests - [jpa]10576ms
22:35:31.366 [main] INFO ColaDemoApplicationTests - [m]138ms
可以说相差差不多10倍了吧?这仅仅只是1000条数据。让我们试试10000条
22:36:48.505 [main] INFO ColaDemoApplicationTests - [jpa]8081ms
22:37:05.005 [main] INFO ColaDemoApplicationTests - [m]613ms
# 再试试10w条
22:38:49.085 [main] INFO ColaDemoApplicationTests - [jpa]65710ms
22:39:09.844 [main] INFO ColaDemoApplicationTests - [m]9448ms
那么这样能看出来很⼤的差距了吧?为什么会差距这么⼤呢?我们看看saveAll()源码
@Transactional
@Override
public <S extends T> List<S> saveAll(Iterable<S> entities) {
List<S> result = new ArrayList<S>();
for (S entity : entities) {
result.add(save(entity));
}
return result;
}
@Transactional
@Override
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
(entity);
}
}
从上⾯可以看出来是⼀条条save进去的并且save⾥⾯还会去判断这个主键是否为空也就是说n条循环n条if判断,那样性能肯定是衰减得⾮常多的拉
结论
我在⽹上看到加⼊以下这些参数可以变成批量的,但是笔者试过根本没⽤,可能想要解决这个问题,需要重写他的saveAll()⽅法然后分⽚去插⼊或者更新这样性能会好很多。
spring.jpa.properties.hibernate.jdbc.batch_size=10000
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true
spring.jpa.der_inserts=true
spring.jpa.der_updates=true
当然今天我仅仅是⽤jpa的性能跟mybatis⽐较,但是作为⼀个码农深知,技术是为业务服务的。Jpa当然也有他的好处,例如创建⼀些⽅法findAllByIdIn(List ids)就可以直接获取到以这个条件查询的列表,还有findAllByOrderIdAndOrderType(String orderId, String orderType)这种⼀样也可以,可以说⾮常的⽅便,也不需要再去写sql,他会全⾃动的完成你的查询操作。
⼩结
开发⼀个⼩型项⽬,Jpa效率肯定是⽐Mybatis⾼的,但是因为业务需求迭代更新越来越快,Jpa明显是满⾜不了很多东西,⽽且维护起来看Sql也是⽐MyBatis难。所以我更偏向于Mybatis,写的Sql也更加简洁更容易维护。
到此这篇关于Mybatis与Jpa的区别和性能对⽐的⽂章就介绍到这了,更多相关Mybatis与Jpa区别和性能内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论