Разница между 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);
}
}
- Из вышеизложенного видно, что сохранения вводятся одно за другим, и сохранение также будет определять, пуст ли первичный ключ, то есть 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 более лаконичен и прост в обслуживании.