JAVASpring

Jpa 和 mybatis

一、JPA


1. 简单介绍

作为规范,Java Persistence API关注持久性,它将Java对象的创建过程和具体的创建形式解耦。并非所有Java对象都需要持久化,但大多数应用程序都会保留关键业务对象。JPA规范允许您定义应该保留哪些对象,以及如何在Java应用程序中保留这些对象。

Java持久性API(JPA)是Java的一个规范。 它用于在Java对象和关系数据库之间保存数据。 JPA充当面向对象的领域模型和关系数据库系统之间的桥梁。

由于JPA只是一个规范,它本身不执行任何操作。 它需要一个实现。 因此,像Hibernate,TopLink和iBatis这样的ORM工具实现了JPA数据持久性规范。

JPA本身不是一个工具或框架; 相反,它定义了一组可以由任何工具或框架实现的概念。虽然JPA的对象关系映射(ORM)模型最初基于Hibernate,但它已经发展了。同样,虽然JPA最初打算用于关系/ SQL数据库,但是一些JPA实现已经扩展用于NoSQL数据存储。支持JPA和NoSQL的流行框架是EclipseLink,它是JPA 2.2的参考实现。

  • JPA是Java Persistence API的简称,中文名Java持久层API 。
  • 是 Java EE 5.0 平台标准的 ORM规范,使得应用程序以统一的方式访问持久层。既然是规范,那肯定就需要技术来实现这个规范,所以Hibernate3.2+、TopLink 10.1.3以及OpenJPA都提供了JPA的实现。

2. JPA的优势

  • 标准化 :提供相同的访问API,保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
  • 简单易用,集成方便 :JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单。
  • 和JDBC的查询能力差不多 :JPA的查询语言是面向对象而非面向数据库的,JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
  • 支持面向对象的高级特性 :JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型。面向对象也避免了程序与数据库 SQL 语句耦合严重,比较适合跨数据源的场景(一会儿 MySQL,一会儿 Oracle 等)。

3. 用JPA创建实体类

// lombok注解,自动生成get、set方法
@Data
// 生成无参构造函数的注解
@NoArgsConstructor
// 生成有参构造函数的注解
@AllArgsConstructor
@Entity
// @Table注解是确定表名,不写这个注解的话,默认类名就是表名
@Table (name ="user")
public class User  implements Serializable {
	// 序列化,要继承上面的序列化接口
	private static final long serialVersionUID =  524258970393766098L;

	/**
	 * 自增id
	 */
	 // 指定列名
   	@Column(name = "user_id" )
	@Id
	private Long userId;

	/**
	 * 登录名
	 */
   	@Column(name = "username" )
	private String username;
	
	/**
	 * 登录密码
	 */
   	@Column(name = "password" )
	private String password;

	/**
	 * 性别
	 */
   	@Column(name = "user_sex" )
	private String userSex;

	/**
	 * 手机
	 */
   	@Column(name = "user_tel" )
	private String userTel;

	/**
	 * 爱好
	 */
   	@Column(name = "user_hobby" )
	private String userHobby;

	/**
	 * 创建时间
	 */
   	@Column(name = "create_time" )
	private Long createTime;

	/**
	 * 修改时间
	 */
   	@Column(name = "update_time" )
	private Long updateTime;

}

4. 用JPA书写repository层

public interface CreditRepository extends PagingAndSortingRepository<CreditDO, Long> {
    List<CreditDO> findCreditDOSByUcc(String ucc);

    Page<CreditDO> findAllByUcc(String ucc, Pageable pageable);

    Long countAllByCreatedAtAfterAndCreatedAtBeforeAndTypeAndUcc(Date after, Date before, CREDIT_TYPE t, String ucc);

    CreditDO findCreditDOById(Long creditId);

    Boolean existsCreditDOByUccAndType(String ucc, CREDIT_TYPE t);

}
package com.lm.jpaDemo.repositroy;

import com.lm.jpaDemo.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends JpaRepository<User, Integer>, CrudRepository<User, Integer> {


    /**
     * 自定义的查询方法
     * @return
     */
    @Query("select u from User u where u.username = ?1")
    public User findByName();


    /**
     * 使用hql进行删除操作
     * @param id
     */
    @Modifying
    @Query("delete from User u where u.userId = ?1")
    public void deleteById(Integer id);

    /**
     * 使用sql进行删除操作
     * nativeQuery = true属性标识启用sql操作,即value中写操作将被当作sql语句进行操作,而不是hql语句
     * @param id
     */
    @Modifying
    @Query(value = "delete from User u where u.user_id = ?1", nativeQuery = true)
    public void deleteById2(Integer id);

二、mybatis


1. 简单介绍

  • MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。
  • MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。
  • MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。

2. mybatis的优势

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。
  • sql写在xml里,便于统一管理和优化 : 通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射 : 提供对象关系映射标签,支持对象关系组建维护。 提供xml标签,支持编写动态sql。

3. 用mybatis创建的实体类

实体类中的参数和数据库表中的参数一一对应。根据数据库建表。

public class User implements Serializable {
		
	private int id ;
	private String username;
	......
}

4. 用mybatis创建mapper层

public interface IUserMapper {
	/**
	* 查询所有操作
	* @return
	*/
	List<User> findAll();
}

5. 创建创建mybatis的主配置文件

<configuration>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置Mysql的环境-->
        <environment id="mysql">
            <!--配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源(连接池)-->
            <dataSource type="POOLED">
                <!--配置连接数据库的四个基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/db1" />
                <property name="username" value="root" />
                <property name="password" value="a" />
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="Mybatis/IuserMapper.xml" />
    </mappers>

</configuration>

6. 创建mybatis映射配置文件

<mapper namespace="com.Mapper.IUserMapper" >
    <select id="findAll" resultType="com.Pojo.User" >
        select * from usr
    </select>
</mapper>

7. 编写测试类

......

InputStream in = Resources.getResourceAsStream("mybatis/MapperConfig.xml");
//创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession创建Mapper接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//使用代理对象执行方法
List<mybatis_user> users = userMapper.findAll();
for (mybatis_user muser : users){
    System.out.println(muser);
}
session.close();
in.close();

......

三、对比 JPA 和 mybatis

其实JPA和mybatis大体上没什么区别,架构上很相似,mybatis就是mapper层 :

JPA就是repository层

其他都一样的

  • spring data jpa实现了jpa(java persistence api)功能,即可以实现pojo转换为关系型数据库记录的功能,通俗来讲就是可以不写任 何的建表sql语句了。jpa是spring data jpa功能的⼀个⼦集。 ⽽mybatis并没有jpa功能,建表语句还是要⾃⼰写的。
  • spring data jpa是全⾃动框架,不需要写任何sql。⽽mybatis是半⾃动框架,需要⾃⼰写sql,mybatis-plus为mybatis赋能,使其也可以基本上不需要写任何模板sql。
  • jpa对于单表的简单查询确实简单方便又实用。
  • mybatis ,只能说对于多表查询确实是比较支持。尤其是在业务逻辑多是多表关联的情况下,mybatis绝对比jpa要更加适合。无论是以后的维护还是业务的变更都方便不少。

心得总结


其实要承认,一个东西用久了都会有习惯心理。mybatis和jpa,两个持久层框架。从底层到用法都不同。但是实现的功能是一样的。所以说一直以来颇有争议。常年混迹于各大qq技术交流群。见过jpa的死忠粉也见过mybatis的铁杆。作为一个不到两年工作经验的小菜鸟来说,你让我分析源码,讲什么底层实现我是讲不出来的。只能作为一个使用者,来谈谈自己对这两个框架的理解。

首先,都知道jpa的前身是著名的ssh中的h——>Hibernate。我到现在还记得学习Hibernate时对它产生的讲解:一个希望不用写sql语句来操作数据库的懒到愿意为此开发一个框架的创始人,其实也够奇葩到值得记住了。而现在的jpa,我觉得主旨也确实在贯彻这个理念。你要承认,jpa的对于单表的简单查询确实简单方便又实用。但是同时,对于多表关联和复杂查询,起码目前为止,要么把复杂查询拆成多个简单查询,要么宁可直接一个nativeQuery = true来原生查询。如果这两点都没能满足你业务的需求,我不敢下定结论说你的设计有问题,但是如此复杂的业务逻辑,身为小白的我实在无法给你建议了。

然后说到mybatis,原谅我入行时间比较晚。从我开始学习java他就已经出现了。听说过他前身好像是ibatis,但是具体就不太了解了。使用上来讲,在那个boot还没有发布的年代,mybatis也曾经是每个程序员必备的基本技能。刚接触的时候mapper映射在我眼中简直是神奇。也算是用了半年多,多少有一定的了解。在这里基本的使用就不多介绍了,反正我一直所应用的也基本都是crud。没到多高深的地步。只能说对于多表查询确实是比较支持。尤其是在业务逻辑多是多表关联的情况下,mybatis绝对比jpa要更加适合。无论是以后的维护还是业务的变更都方便不少。

可能我这么说大家还是不太理解什么时候用jpa什么时候用mybatis。我举个例子:现在业务上A,B,C,D四个表。如果你每个表都会在业务中用到,都需要有单独的增删改查,虽然有一定的关联关系,但是这种情况用jpa就比较合适。ABCD四个java实体不说,每个实体要对应一个repository。然后再repository层进行crud的编写。但是如果业务上A,B,C,D四个表。这四个是关联关系,你几乎不会单独对A,B,C进行操作,而且展现出来的也是D,那么这个时候jpa的使用就会很麻烦,因为你还是要四个实体四个repository。在一个接口中四个repository挨个调用一次。虽然也能完成业务逻辑,但是复杂又麻烦。还要考虑原子性什么的。所以这个时候用mybatis比较合适了。

其实说到这大概对于什么样的业务应该采用哪个在思维上应该有个简单的区分了。不过很多时候很多项目不是能一下子分辨出来属于哪种的。所以还是需要具体判断的。虽然工作才一年多,但是外包让我经历了多个项目的经验告诉我,千万别相信那些所谓的“某某大佬”随便给你的建议。(我是指那些连具体业务都不知道就给你建议jpa好还是mybatis好的那种。如果真的是大佬而且愿意为你的项目深入分析并且给出答案,那还是值得参照的)因为以前有一次在老板给了我一个小项目让我独立完成的时候我选择了咨询群里的大佬。记得很清楚当时大佬给的意见就是mybatis。还说了mybatis的好多优点。然后我就自然而然的用了。结果嘛,大家能想到我一个人能完成的项目会有多小,业务多简洁。虽然用mybatis也做完了。但是现在想想,要是换成jpa肯定会更加快速方便的开发。我讲这段经历绝对没有别的意思,只是想告诉大家业务怎么样还是自己最清楚。很多时候我们的询问可能不是很全面,所以别人给的建议也不是很合适。

然后还有一些额外的东西。比如说spring家族的态度。我不知道各位有没有跟我一样的大众心理。一个jar包。只要是org.springframework.boot这个分组的,就比较信赖。毕竟有那么庞大的家族做后盾呢~~而且boot真的是封装的越来越具体了~~~反正依稀记得以前spring创建个项目,还要配置这个那个的,偶尔马虎下还报个错。一个结构要搭好一会儿的(也可能是我当时比较菜,但是确实要配置一些东西)而现在呢,spring boot,差不多创建了,依赖导一下就可以跑。真的是相当方便。方便到前一段时间群里一个小孩子问了一个spring 配置的问题,我居然觉得有点想不起了~~哎~~spring boot用多了,都把人用成sb了~~~哈哈,开玩笑的,别当真。反正现在代码的高度封装让我们用什么都更加简单了。而boot对jpa的封装,反正我个人是觉得在单纯的配置上面,除了在配置文件中连接下数据库然后添加个data-jpa的依赖,搞定了就。这也是个人比较喜欢jpa的一点。部署是真的简单。而且官方文档还很全面。也在持续维护更新。我觉得单纯从spring的角度,jpa就值得一试。当然了,这个属于个人心态,但是如果是新手在自己做练手项目的时候,我还是推荐jpa。

对了,再额外安利一下,这个就涉及到了个人的使用经验。以前只有mybatis有代码生成器,所以基于这个原因有一段时间我还比较喜欢用mybatis。但是现在jpa也有了代码生成器。从表到实体和从实体到 表都可以自动生成的。小白们别手敲啦~~~(ps:是因为我以前做过这种事所以在此提醒一下跟我一样白的小盆友,知道的可以掠过)。至于代码生成器的使用,只要你知道了这个概念去百度都能找到用法,在这里我就不多说了。实在不知道的也可以问我,我要是看到了会回的,虽然我觉得找我不如自己百度呢。

然后再说个题外话,其实jpa和mybatis都是很有必要学的。因为遇到的项目会各种各样,所以两者各有长短。还有就是如果自己没话语权的时候,最好上级让用啥就用啥。注意!我说的是最好。如果说你们team氛围比较好,然后领导比较愿意接受意见什么的,你出与实际考虑确实有不同的意见可以提出来。不然的话还是老老实实听指挥吧。别管你以为有多不合理。我不是在宣扬什么消极理念。而且在一个team中领导所考虑的可能和你考虑的点不一样。或者说你知道的不太全面等。没必要非要为了所谓的自己为正确然后最后弄的大家都不愉快。尤其是最后还可能结果也不会想你想的那样。大家都是做技术的,有点自视清高或者说自己的见解很正常。但是切记人还是要谦卑。给大家讲一个实际发生的故事。

我们team一直是手写接口文档,然后人工维护的。确实现在有很多文档生成工具,我自己也用过swagger做过demo,但是团队里有的人不会用,而且其实维护起来也很麻烦(可能是没用习惯的麻烦,这不是主要的),而且我们公司接的项目都比较小。所以领导说就手工维护接口文档吧。然后前一段时间来了个实习的小孩,可能是学习确实很努力,接触的技术很多。然后一开始整天也干劲儿满满的自觉加班在公司学习到很晚那种。后来开了个项目,小孩看到我们手工维护接口可能是觉得比较low,所以跟我们领导建议用swagger。然后我们领导就很委婉的说他回去了解了解,考虑考虑再说,先这么手工维护吧。然后自那以后我们再手动改接口,他就会讲这样怎么怎么,巴拉巴拉的。重点是有一次我们team中工作时间比较久的一个大哥因为接口对接没对接好,所以测试的时候有点小bug,这个孩子又开始抱怨说用手写文档怎么怎么不好。。然后我们领导就爆发了,劈里啪啦一顿训斥,大概意思就是这里的人谁不比他有经验啊,他优越什么啊,之所以不改是因为要前端后端都要熟悉这个框架,没必要。。然后那以后这个小孩沉默多了,也不知道是顿悟了什么还是说生气。后来不久这个小男孩就走了。辞职还是被劝退也都不知道。其实单单从这个故事看,一个swagger的事,说不上谁对谁错的。非要说的话,我们一个外包公司,肯定是需求对付做完就行了,老板不愿意拿时间来让员工学习一些没必要的技能。从小男孩的角度,一个实习生没有决定权却非要坚持主见。这个也算是职场经验了 吧~~~说着说着跑题了~~~

反正核心几句话:

  • 1 jpa和mybaits各有优缺点。
  • 2 使用哪个合适要结合具体的业务进行分析。
  • 3 当你没有决定权的时候,最好领导让用什么用什么。