Mybatis与Jpa的区别和性能对比总结

前言

这几天听朋友说JPA很好用,根本不用写sql。我在想一个程序员不写sql还能叫程序员?而且越高级的工具封装越多的工具,可拓展性和效率就非常的低,况且我本身非常不喜欢过于封装的东西,平时喜欢手写sql,所以一直都是用mybatis去写业务。然后发现jpa的saveAll()批量插入批量更新速度太慢了,导致一些用excel导入的一些东西非常慢,弄得原本同步可以解决的事情每次导入都要开启一个异步,个人感觉这种做法非常不好。因为异步其实就是对当前的业务不影响去另外的时间段去做,例如跑定时任务,异步更新增量信息等。代码里非常多异步包异步的东西,也就是说excel导入是异步,然后jpa又慢,异步里面又包涵异步,整个链路非常长,可能发生问题都要排查半天。

安装jpa和mybatis

<dependency>
	<groupId>org.mybatis.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}, #{item.metricItem})
    </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<com.kakki.colademo.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);
            com.kakki.colademo.gatewayimpl.database.dataobject.TestMybatis testMybatis = new com.kakki.colademo.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);
        }
        StopWatch jpa = new StopWatch();
        jpa.start();
        testRee.saveAll(jpaList);
        jpa.stop();
        log.info("[jpa]{}ms", jpa.getTotalTimeMillis());

        StopWatch m = new StopWatch();
        m.start();
        metricMapper.insertList(mybatisList);
        m.stop();
        log.info("[m]{}ms", m.getTotalTimeMillis());

    }

}

22:35:10.708 [main] INFO  c.e.c.ColaDemoApplicationTests - [jpa]10576ms
22:35:31.366 [main] INFO  c.e.c.ColaDemoApplicationTests - [m]138ms

可以说相差差不多10倍了吧?这仅仅只是1000条数据。让我们试试10000条

22:36:48.505 [main] INFO  c.e.c.ColaDemoApplicationTests - [jpa]8081ms
22:37:05.005 [main] INFO  c.e.c.ColaDemoApplicationTests - [m]613ms
# 再试试10w条
22:38:49.085 [main] INFO  c.e.c.ColaDemoApplicationTests - [jpa]65710ms
22:39:09.844 [main] INFO  c.e.c.ColaDemoApplicationTests - [m]9448ms

那么这样能看出来很大的差距了吧?为什么会差距这么大呢?我们看看saveAll()源码

    @Transactional
	@Override
	public <S extends T> List<S> saveAll(Iterable<S> entities) {

		Assert.notNull(entities, "Entities must not be null!");

		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 {
			return em.merge(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.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_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区别和性能内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot整合Mybatis、JPA、Redis的示例代码

    引言 在springboot 项目中,我们是用ORM 框架来操作数据库变的非常方便.下面我们分别整合mysql ,spring data jpa 以及redis .让我们感受下快车道. 我们首先创建一个springboot 项目,创建好之后,我们来一步步的实践. 使用mybatis 引入依赖: <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-

  • MyBatis还是JPA?终于有答案了

    对于一个和数据库打交道的程序员来说,很快会面临着一个艰难的选择.到底是选择MyBatis还是JPA呢? 很多人说,技术选择,都要根据需求来,这个没错.但是,除了需求,还有很重要的一个环节,那就是队友的水平.如果你选择了一些比较高级的技术,那么就是在给整个团队埋坑. JPA的抽象层次更高,代码写起来也更简洁,但是它一点都不简单.虽然经过了多次的培训,我呆过的几个团队,还是把它用的和屎一样. 我扔掉了JPA 我仔细想了一下,有下面几点原因,造成了JPA在很多团队根本就玩不下去. JPA适合业务模型固

  • Spring jpa和mybatis整合遇到的问题解析

    前一阵子接手了一个使用SpringBoot 和spring-data-jpa开发的项目,后期新加入一个小伙伴,表示jpa相比mybatis太难用,多表联合的查询写起来也比较费劲,所以便加入了mybatis的支持 开始的时候 @Configuration @EnableJpaRepositories("com.xxx.xxx.repository") class JpaConfig 使用这种方式去配置的jpa,遇到一个问题,就是能select 但是不能save,所以就修改为配置文件的方式

  • Mybatis与Jpa的区别和性能对比总结

    前言 这几天听朋友说JPA很好用,根本不用写sql.我在想一个程序员不写sql还能叫程序员?而且越高级的工具封装越多的工具,可拓展性和效率就非常的低,况且我本身非常不喜欢过于封装的东西,平时喜欢手写sql,所以一直都是用mybatis去写业务.然后发现jpa的saveAll()批量插入批量更新速度太慢了,导致一些用excel导入的一些东西非常慢,弄得原本同步可以解决的事情每次导入都要开启一个异步,个人感觉这种做法非常不好.因为异步其实就是对当前的业务不影响去另外的时间段去做,例如跑定时任务,异步

  • 详谈MySQL和MariaDB区别与性能全面对比

    MariaDB数据库介绍 MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可.开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险,因此社区采用分支的方式来避开这个风险. MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品. MariaDB由MySQL的创始人麦克尔·维德纽斯主导开发,他早前曾以10亿美元的价格,将自己创建的公司MySQL卖给了SUN,此后,随着SUN被甲骨文收购

  • 关于Mybatis与JPA的优缺点说明

    目录 Mybatis与JPA的优缺点 JPA java持久层API JPA优势 Mybatis优点 Mybatis缺点 JPA与Mybatis的区别 JPA就是把mapper层的接口换成repository的接口 JPA的repository Mybatis与JPA的优缺点 JPA java持久层API 可理解为一种规范,Hibernate就是其具体一个实现.它的实现应用是Spring DataJpa,Spring提供了一套简化开发框架,按照约定好的方法命名规则,编写dao层接口,即可在不编写实

  • 深入浅析Mybatis与Hibernate的区别与用途

    有很长一段时间对mybatis是比较陌生的,只知道与Hibernate一样是个orm数据库框架.随着使用熟练度的增加,发现它与Hibernate区别是非常大的,应当结合不同的情况分析选用. 有很长一段时间对mybatis是比较陌生的,只知道与Hibernate一样是个orm数据库框架.随着使用熟练度的增加,发现它与Hibernate区别是非常大的,应当结合不同的情况分析选用.结合至今为止的经验,总结出以下几点: 1. hibernate是全自动,而mybatis是半自动 hibernate完全可

  • set rs=conn.execute,set rs=server.createobject(“ADODB.recordset”)的性能对比

    经常用asp的同行,可能会建议用set rs=conn.execute(sql)来代替set rs=server.createobject("ADODB.recordset"):rs.open conn,sql,1,1.还有一些同行更提出了用set rs=conn.execute(sql):res=rs.getRows(100)来优化ASP程序.其实在没有做此实验前,我也是很相信这种方法的.实际效果果真如此吗?经过一番测试,我发现结果远非如此,set rs=server.createo

  • Java for循环和foreach循环的性能对比分析

    目录 for循环和foreach循环的性能对比 普通for循环语法 foreach 循环语法 for与foreach循环效率比较 对于数组来说 对于链表来说 小结一下吧 for循环和foreach循环的性能对比 在公司codereview过程中,发现一个问题,就是有些人循环用的是普通for循环,有些人用的是foreach循环,它们之间有什么区别?应该在什么时候使用这两种循环了? 两种循环的语法格式: 普通for循环语法 for (int i = 0; i < integers.length; i

  • javascript 三种数组复制方法的性能对比

    一. 三种数组复制方法 1. by slice var arr = [1, 2, 3], copyArr; copyArr = arr.slice(); 2. by concat var arr = [1, 2, 3], copyArr; copyArr = arr.concat(); 3. by loop var arr = [1, 2, 3], copyArr = []; for (var i=0, j=arr.length; i 二. 测试环境 浏览器: IE6+, FF 3.5.5, O

  • Vue服务端渲染和Vue浏览器端渲染的性能对比(实例PK )

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司做Vue项目的时候,一直苦于产品.客户对首屏加载要求,SEO的诉求,也想过很多解决方案,本次也是针对浏览器渲染不足之处,采用了服务端渲染,并且做了两个一样的Demo作为比较,更能直观的对比Vue前后端的渲染. talk is cheap,show us the code!话不多说,我们分别来看两个D

  • Mybatis与Ibatis的区别

    Mybatis与Ibatis的区别: 1.Mybatis实现了接口绑定,使用更加方便 在ibatis2.x中我们需要在DAO的实现类中指定具体对应哪个xml映射文件, 而Mybatis实现了DAO接口与xml映射文件的绑定,自动为我们生成接口的具体实现,使用起来变得更加省事和方便. 这可以说是Mybatis最重要的改进. 注意: 虽然Mybatis支持在接口中直接使用annotation的配置方式来简化配置, 不过强烈建议仍然使用xml配置的方式.毕竟annotation的配置方式功能有限且代码

  • php+mysql prepare 与普通查询的性能对比实例讲解

    php+mysql prepare 与普通查询的性能对比 实例代码如下: <?php class timer { public $StartTime = 0; public $StopTime = 0; public $TimeSpent = 0; function start(){ $this->StartTime = microtime(); } function stop(){ $this->StopTime = microtime(); } function spent() {

随机推荐