JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
Jpa是一个标准,就像JTA、JMS这种一样。Java Persistence API里面定义了一对注解,并没有实现。
JPA的实现框架有:Hibernate EntityManager(RedHat)、TopLink Essentials(Oracle/GlassFish,EJB 3.0中的JPA参考实现),Apache OpenJPA(BEA)、EclipseLink(http://www.eclipse.org/eclipselink/)、JDO等ORM框架。
在Spring家族里,有Spring data jpa(https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference)提供ORM,Spring Data JPA的默认实现是Hibernate,当然也可以是其他的JPA Provider。如Spring Data JPA 1.10支持Querydsl 4、Hibernate 5、OpenJPA 2.4 和 EclipseLink 2.6.1。
所以,JPA跟mybatis没关系。 然而,Spring data jpa的风格却特别优雅,我们可以用mybatis去实现这种风格。
如: Spring对JPA实现的核心的API:
这些,我们完全可以用mybatis去实现。实现无sql的开发过程。
@Entity
@Table(name = "user_role")
public class UserRole {
@Id
private int id;
@Column(name = "user_name")
private String userName;
private String role;
}
public interface UserRoleDao extends CrudRepository<UserRole, Integer> {
List<UserRole> findByRole(String role);
@Query("select u from UserRole u where u.userName like ?1%")
List<UserRole> findByAndSort(String userName, Sort sort);
}
public interface UserRoleDao extends PagingAndSortingRepository<UserRole, Integer> {
Page<UserRole> findByUserName(String username, Pageable pageable);
}
Mybatis的代码生成工具有很多: mybatis-generator、 easycode 等
这些工具是读取数据库表结构,然后按照模板生成entity、mapper、xml文件的。
如果不想下载插件,不想配置数据源,我们完全可以用js去自己生成code。 比如我自己做的一个:https://www.pomit.cn/java/project/sqlToMapper.html
生成代码,虽然提高了开发效率,但是不方便维护。 开发原则:约定大于配置,配置大于代码。所以有很多动态生成mybatis sqlsource的工具,如tk-mybatis、mybatis-plus。
Mybatis的MapperAnnotationBuilder是注解方式sql的处理器,其中parseStatement方法就是对Method上的注解进行解析,生成sqlsource并addMappedStatement,如果实现无sql的方式,只要有自己的parseStatement,并addMappedStatement即可。
那如何实现呢?
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
这就是一个MappedStatement所需要的东西,虽然很多,但是不用担心,真正需要的就几个:
其他的不是很重要。最重要的是SqlSource该怎么写呢?
languageDriver.createSqlSource(configuration, sql, parameterTypeClass);
这里使用configuration、注解的sql和参数一起创建了SqlSource。所以,思路来了,我们可以使用Java Persistence API的注解和反射去拼接SQL!
同时,我们也可以通过手段获取到Mapper。
@Autowired
private List<SqlSessionFactory> sqlSessionFactoryList;
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
MapperRegistry mapperRegistry = configuration.getMapperRegistry();
List<Class<?>> mappers = new ArrayList<>(mapperRegistry.getMappers());
// 可以记录下所有的mapper
}
// 此后可以扫描mapper的所有方法,可以按照方法是否存在注解去兼容mybatis常规写法和自动生成代码。
在Spring环境下,我们很容易获取到SqlSessionFactory,通过SqlSessionFactory,我们就可以获取到我们想要的东西: 这里,我们可以获取到Configuration和mappper。这两个很有用, 在MapperAnnotationBuilder中,会通过Configuration和mappper生成MapperBuilderAssistant,然后MapperBuilderAssistant调用addMappedStatement添加自定义MappedStatement。
为了自动生成SQL,就需要我们根据实体去拼接SQL。那就解决两个问题:生成哪些方法的sql、实体从哪儿来。 当然有办法:
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.Id;
@Table(name = "f_auth_apply")
public class UserAuthApply {
@Id
@Column(name = "user_name")
private String userName;
@Column(name = "role_name")
private String roleName;
}
Class<?> interfases[] = mapper.getInterfaces();
if (interfases == null || interfases.length < 1) {
return NO_MAPPER;
}
for (Class<?> interfase : interfases) {
if (ReflectUtil.checkTypeFit(interfase, JMapper.class)) {
if (interfase.equals(SimpleShardingMapper.class)) {
return SHARDING_MAPPER;
} else if (interfase.equals(PagingAndSortingMapper.class)) {
return PAGESORT_MAPPER;
} else {
return CRUD_MAPPER;
}
}
}
Method[] methods = mapper.getMethods();
for (Method method : methods) {
if (method.getAnnotations() == null || method.getAnnotations().length < 1) {
//无注解,代表是需要被生成sql的方法,有注解无视即可,会自己走mybatis的逻辑。
}
}
@Table(name="user_info")
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="user_name")
private String userName;
@Column()
//@ShardingKey(prefix="_", methodPrecis="getTable", methodRange = "getTables")
private String mobile;
@Column()
private String name;
@Column()
private String passwd;
@Column()
private String valid;
}
import org.apache.ibatis.annotations.Mapper;
import com.github.ffch.boot.domain.UserInfo;
import com.github.ffch.jpamapper.core.mapper.CrudMapper;
@Mapper
public interface UserInfoDao extends CrudMapper<UserInfo, String> {
List<UserInfo> findByUserName(String userName);
int deleteByUserName(String userName);
@Select({
"<script>",
"SELECT ",
" user_name as userName,",
"role as role",
"FROM user_info",
"</script>"})
List<UserInfo> selectAll();
}
@Mapper
public interface UserInfoSortDao extends PagingAndSortingMapper<UserInfo, String>{
Page<UserInfo> pageByPasswd(String passwd, Pageable pageable);
List<UserInfo> sortByPasswd(String passwd, Sort sort);
}
这种方式仅仅可以固定的SQL么,非也。
@Result(property = “userList”, javaType=List.class, many =@Many(select=“selectUsersByGroupId”), column = “group_id”)})
这种形式,对ResultType进行解析,隐式创建一个MappedStatement。<bind name=\”patternTable\“ value=\”@com.cff.springbootwork.sharding.jdbc.domain.ChatInfo@findTable(liveId)
, 这种形式可以根据方法动态生成表名。下面是三年前写的一个小工具: https://www.pomit.cn/jpa-mapper/#/
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有