JPA思想架构、Mybatis与Hibernate、通用Mapper的使用
什么是JPA?
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中
传统的数据库操作,以编写sql语句的方式,这种方式是面向过程的编程语言。由此提出,是否能以面向对象的方式操作数据库?如:insert(User)是实现新增的操作。
JPA的起源与发展
JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它又不限于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索,能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。Hibernate3.2+、TopLink 10.1.3以及OpenJPA都提供了JPA的实现。
以Hibernate为例,操作数据库时,其原理是将对象通过反射的方式再次编译为sql语句。这种方式会在底层生成多条的sql语句,因此在数据量较大的数据库中性能较低。假设在执行insert(User)的sql操作时,会首先查询数据库中是否还有该数据,如果没有,再执行insert语句。
之后,经过Hibernate时代后便产生Mybatis框架,其优点在于继承了Hibernate自动化的映射,通过直接操作sql的方式提高性能。目前,许多开源社区(github、gitee等)也开放了通用mapper工具类方便减少sql语句的编写。
Hibernate与Mybatis
MyBatis,编写原生态Sql语句,不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
Hibernate,完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、mysql等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。
区别 | Hibernate | Mybatis |
---|---|---|
特性 | 较完整的ORM映射 | 基本的字段映射 |
日志系统 | 较健全,涵盖异常,优化、缓存、sql记录、脏数据警告等 | 基本功能 |
使用 | 配置复杂,开发效率低,可移植 | 容易上手 |
性能 | 不易维护,有局限性 | 灵活度较高,直接操作sql |
耦合度 | 强大的映射,低耦合 | 取决于sql编写,通用性较低 |
缓存机制 | 较好,还可以使用第三方缓存 | 二级缓存机制较差 |
JPA三大技术
ORM映射元数据
JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中
API
用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来
查询语句
这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
JPA的优势
JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
具有容器级特性的支持
JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
通用mapper(abel533)的使用
(以主流框架mybatis为例)
6.1 引入依赖或导入jar包
<!-- 通用Mapper --> <dependency> <groupId>com.github.abel533</groupId> <artifactId>mapper</artifactId> <version>${mapper.version}</version> </dependency> <!-- 依赖于JPA的注解 --> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency>
6.2 Mapper插件引入
<!-- mybatis-config.xml --> <configuration> ... <!-- 通用Mapper插件 --> <plugins> <plugin interceptor="com.github.abel533.mapperhelper.MapperInterceptor"> <!--主键自增回写方法,默认值MYSQL,详细说明请看文档 --> <property name="IDENTITY" value="MYSQL" /> <!--通用Mapper接口,多个通用接口用逗号隔开 --> <property name="mappers" value="com.xxx.mapper.XxxMapper" /> </plugin> </plugins> </configuration>
6.3 定义Mapper接口
- mybatis的注解形式用法
import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; //此处省略User对象的创建 public interface UserMapper { @Select("select * from user") public List<User> getSelectUser(); @Update("update user set userName=#{userName} where id=#{id}") public void getUpdateUser(User user); @Insert("insert into user(userName,userAge) values(#{userName},#{userAge})") public void getInsertUser(User user); @Delete("delete from user where id=#{id}") public void getDeleteUser(int id); }
通用Mapper的调用形式
定义Mapper接口继承通用Mapper<泛型>,此处必须指定泛型
public interface ItemMapper extends 通用Mapper<Item>{ List<Item> findAll(); } //架构Pojo对象 @Table(name="tb_item") //与数据库中表名对应 public class Item extends BasePojo{ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id;//商品id号 private String title;//商品标题 private String sellPoint;//商品卖点信息 private Long price;//商品价格 private Integer num;//商品数量 private String barcode; //条形码 private String image;//商品图片信息 private Long cid;//商品分类id private Integer status;//状态 1:正常 2:下架 3:删除 //setter、getter方法
a)表名默认使用类名,驼峰转下划线,如
UserInfo
默认对应的表名为user_info
. b)表名可以使用
@Table(name = "tableName")
进行指定,对不符合第一条默认规则的可以通过这种方式指定表名. c)字段默认和
@Column
一样,都会作为表字段,表字段默认为Java对象的Field
名字驼峰转下划线形式. d)可以使用
@Column(name = "fieldName")
指定不符合第3条规则的字段名 e)使用
@Transient
注解可以忽略字段,添加该注解的字段不会作为表字段使用. f)建议一定是有一个
@Id
注解作为主键的字段,可以有多个@Id
注解的字段作为联合主键. g)默认情况下,实体类中如果不存在包含
@Id
注解的字段,所有的字段都会作为主键字段进行使用(这种效率极低).
后续如有想了解通用Mapper底层的原理实现的,欢迎交流讨论~~~
1.通用Mapper的架构思路的引入
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.scripting.xmltags.MixedSqlNode;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode;
import com.github.abel533.mapper.MapperProvider;
import com.github.abel533.mapperhelper.EntityHelper;
import com.github.abel533.mapperhelper.MapperHelper;
2.通过反射动态执行sql的过程
……