spring-boot JPA 集成使用总结以及基本使用介绍 入门案例等 And、Or、Between、Like、In、NotIn等接口命名字 EntityManager 自定义、 @Query用法等

JPA 介绍

JPA 是 Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

Sun 引入新的JPA ORM规范出于两个原因:
其一,简化现有Java EE和Java SE应用开发工作
其二,Sun希望整合ORM技术,避免ORM 框架各自为营。

JPA 规范本质上就是一种ORM规范,不是ORM框架
因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。
JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,也是一种JPA实现。

JPA 集成使用

Maven依赖

spring-boot

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

spring-boot 配置

spring:
  application:
    name: myApplicationName
  datasource:
    url: jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    hibernate:
# 自动更新表结构 自动建表
      ddl-auto: update
# 显示sql
    show-sql: true

spring.datasource
指定数据源链接等

数据实体定义

相关资料
@Entity 相关学习介绍 springJPA
JPA @entity@table@index 定义表以及序列案例
@Id 自增设定

通过 jpa 上面的配置

spring:
  jpa:
    hibernate:
# 自动更新表结构 自动建表
      ddl-auto: update

可以实现当通过注解完成实体定义时,启动项目时将建立对应的表结构

实体定义实例

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
import java.util.Date;

// 以下三个为 lombok 与 jpa 无关
@Data
@NoArgsConstructor
@AllArgsConstructor

// javax 自带注解
@Entity(name = "my_test")
// 定义索引列 多个列时 columnList 中使用 , 分割
@Table(indexes = {@Index(columnList = "per_code", name = "index_resources_code")})
public class MyTestEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "per_name", length = 64)
    private String perName;

    @Column(name = "per_code")
    private String code;

    @Column(name = "business", columnDefinition = "TEXT")
    private String business;

    /**
     * active标记
     */
    @Column(name = "active")
    private boolean active;

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

    /**
     * 更新时间
     */
    @Column(name = "update_time")
    private Date updateTime;

    /**
     * 创建者
     */
    @Column(name = "creator_id")
    private Long creatorId;

    /**
     * 创建部门
     */
    @Column(name = "create_dept_id")
    private Long createDeptId;

}

这里 第一次启动 的时候发现 启动失败,报错没有找到索引列,可能建表和字段在建立索引之后,先将索引注解去除,再次启动表自动创建成功,结构如下
可以看到默认长度 Long 为20, string 为 255, length 用于指定长度,columnDefinition 可以额外定义列具体类型和其他定义
在这里插入图片描述
加上索引注解,再次启动后启动成功,索引建立成功
在这里插入图片描述

附:
@Entity
作用:指定当前类是实体类。
@Table
作用:指定实体类和表之间的对应关系。
属性:
name:指定数据库表的名称
@Id
作用:指定当前字段是主键。
@GeneratedValue
作用:指定主键的生成方式。。
属性:
strategy :指定主键生成策略。
@Column
作用:指定实体类属性和数据库表之间的对应关系
属性:
name:指定数据库表的列名称。
unique:是否唯一
nullable:是否可以为空
inserttable:是否可以插入
updateable:是否可以更新
columnDefinition: 定义建表时创建此列的DDL
secondaryTable: 从表名。

创建DAO 接口层

与其他成形的框架一致,只要继承这些便提供了基本查询方法,同时支持自定义接口
先看最基本的查询方法

import com.dtdream.dthink.dtalent.dmall.openplat.model.entity.MyTestEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;

@Repository
public interface MyTestRepository extends JpaRepository<MyTestEntity, Long>, JpaSpecificationExecutor<MyTestEntity> {

}

JpaRepository, JpaSpecificationExecutor 里面的泛型第一个都是实体本身即可
Repository(仓库,存放处)Specification 规格 Executor执行者
JpaRepository 泛型第二个为 ID 的类型
在这里插入图片描述

继承Jpa 的基础类后提供的方法如下

首先创建 Service 并注入Dao 接口对象

import com.dtdream.dthink.dtalent.dmall.openplat.dao.MyTestRepository;
import com.dtdream.dthink.dtalent.dmall.openplat.service.MyTestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
@Slf4j
public class MyTestServiceImpl implements MyTestService {

    @Autowired
    private MyTestRepository myTestRepository;


    @Override
    public void test() {

    }
}

jpa 提供的基础查询是 find 开头
在这里插入图片描述
统计计数类
在这里插入图片描述
删除
在这里插入图片描述
通过Id 单个获取
在这里插入图片描述
判断是否存在
在这里插入图片描述
保存实体
在这里插入图片描述

接口层提供的自动组合方法(IDEA 提示功能)

相当我们站在了更高的角度,面向接口编程,而具体实现由下游实现了Jpa 规范的厂商提供各自的 SQL 化。

通过这种方法也可以实现基本的条件租户完成查询等功能。
例如下面这样:
在这里插入图片描述
我们只需要根据接口的单词句意组合即可,find 依旧是查询,get 也支持
在这里插入图片描述
在这里插入图片描述

By后面即是我们定义的实体的某些属性,当我们不选择属性名后面的其他单词时就是单纯的等于查询。
例如下面相当于:
在这里插入图片描述
我要通过active 字段和 code 两个字段查询不给任何其他词汇说明是需要两个字段与后面的值相等即一般的 “=” 查询,两个字段的入参分别为 第一个和第二个入参的值。

同时在服务层中我们可以直接使用该方法,不需要理会实现,实现由底层自动完成拼装。
在这里插入图片描述
需要注意的是 单词的拼写必须完全正确同时符合驼峰命名写法用于区分属性字段。

跟在属性后面的其他单词意义等整理如下

前缀,如find、findBy、get、getBy 对剩下部分进行解析
如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。

可能会存在一种特殊情况,比如某一个实体包含一个 user 的属性,也有一个 userName 属性,此时会存在混淆。读者可以明确在属性之间加上 “_” 以显式表达意图,比如 “findByUser_Name()”

在查询时,通常需要同时根据多个属性进行查询,且查询的条件也很多(大于,大于等于,小于,小于等于 等等),Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下:

And
等价于 SQL 中的 and 关键字,比如 上面的例子
Or
等价于 SQL 中的 or 关键字
Between
等价于 SQL 中的 between 关键字 需要指定两个入参,作为区间的边界
LessThan
等价于 SQL 中的 “<” 小于
LessThanEqual
等价于 SQL 中的 “<=” 小于等于
GreaterThan
等价于 SQL 中的">" 大于
GreaterThanEqual
等价于 SQL 中的">=" 大于等于
IsNull
等价于 SQL 中的 “is null”
IsNotNull
等价于 SQL 中的 “is not null”
NotNull
等价于SQL 中的 IsNotNull
Like
等价于 SQL 中的 “like” ,但内容需要自己加入 % 通配符,类似于 入参为 “%内容%”
NotLike
等价于 SQL 中的 “not like”,但内容需要自己加入 % 通配符,类似于 入参为 “%内容%”
OrderBy
等价于 SQL 中的 “order by” 以及OrderBy 后面的 Asc Desc 可以跟在最后面。
Not
等价于 SQL 中的 “! =” 或 <>
In
等价于 SQL 中的 “in”,比如 findByUserNameIn(Collection userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
NotIn
等价于 SQL 中的 “not in” 入参与上方一致
After
与 GreaterThan 功效一致,解释为大于
before
与 LessThan 功效一致,解释为小于
StartingWith
内容以什么开头,类似于like 中 去除最前面的 通配符 %,此时入参不需要加入 %
EndingWith
内容以什么结尾,类似于like 中 去除最后面的 通配符 %,此时入参不需要加入 %
Containing
同样用于模糊查询,内容包含什么 但是也需要手动拼接 通配符 %

Native 本地查询,手动SQL 查询, EntityManager

当有些不满足自己的需要或者觉得还不如自己写,那么久可以如下方式

在Servcei 中注入该类
在这里插入图片描述

然后可以通过创建本地 SQL 查询手动自己拼接SQL 完成查询等操作;
例如:
在这里插入图片描述
当查询多个字段返回的结果时不得不使用 Object 一个个转化类型,十分繁琐。

当然这是比较差的一种写法不是很推荐,虽然也有优化一点的方式。但也好不到哪里去,最终还是去写 sql 了。
自定义返回类如下
在这里插入图片描述
个别类来源

import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;

需要的注意的是,这里的自定义返回类中的属性名会和我们上面写的 SQL 去对应
查询的字段别名要和自定义数体类属性对应
即 假如我的实体中有字段叫 createDept 那么 查询中的需要写别名例如 SELECT create_dept AS createDept
需要额外注意的是
如果数据库定义为 bigint 则 返回接收时定义的实体类型也需要是 BigInteger
如果是时间类型,则需要接收类型需要是 Date 类型

@Query 用法

@Query 标记在继承了Repository的自定义接口方法上时,方法名就不需要遵循查询方法命名规则同时也不会去解析校验命名;
注解内定义
在这里插入图片描述

使用占位符,序号从 1开始

import org.springframework.data.jpa.repository.Query;

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

    @Query("select u.id, u.name from User u where u.id=?1")
    List<User> getById(Integer id);
}

也可以使用参数名

import org.springframework.data.jpa.repository.Query;

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

    @Query("select u.id from User u where u.id= :id")
    List<User> getById(@Param("id") Integer id);
}
nativeQuery

当将此值置为 true 时表示使用原生 sql
从定义的实体名查询是 hql 所以 nativeQuery 默认 false

但原生默认返回 object[] 比较麻烦

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

    @Query("select u.id, u.name, d.id, d.name " +
            "from User u, Dept d " +
            "where u.deptId=d.id", nativeQuery = true)
    List<Object[]> findAllForUserDept();
自定义返回类型

使用自定义返回对象时为 返回Java对象 是 hql,所以不支持 nativeQuery 为true
例子:
定义实体

@Data
public class UserDept implements Serializable {

    @JsonProperty("user_id")
    private Integer userId;

    @JsonProperty("user_name")
    private String userName;

    @JsonProperty("dept_id")
    private Integer deptId;

    @JsonProperty("dept_name")
    private String deptName;

    public UserDept(Integer userId, String userName, Integer deptId, String deptName) {
        this.userId = userId;
        this.userName = userName;
        this.deptId = deptId;
        this.deptName = deptName;
    }
}

from 后面都用对象(hql)

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

    @Query("select new com.test.pojo.domain.UserDept(" +
            "u.id, u.name, d.id, d.name ) " +
            "from User u, Dept d " +
            "where u.deptId=d.id")
    List<UserDept> findAllFromUserDept();

    @Query("select new map(" +
            "u.id as user_id, u.name as user_name, d.id as dept_id, d.name as dept_name) " +
            "from User u, Dept d " +
            "where u.deptId=d.id")
    List<Map<String, Object>> findAllFromMap();
}

最后 @Query 代码参考地址 点击跳转原文代码

更新动作的示例代码关键点示例:
@Modifying
加入后认为是更新动作

@Transactional : 若执行时报错 Transactional is required … update/delete 则需要加上事务注解

import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
.........


..........
	@Modifying
    @Transactional(rollbackFor = Exception.class)
    @Query(value = "UPDATE users SET isPublic = :value WHERE id  IN :ids" )
    void updateIsPublicById(@Param(value = "ids")List<Long> isPublicIdList, @Param(value = "value") String value);

当在Query 最后加入 , nativeQuery = true 时将认为要执行普通的 sql 语句,Query 中的语句所有字段的写法应和表设计中保持一致否则失败,不加入 , nativeQuery = true 时将认为时按实体的属性名来查询即 hql 语句。

第一次写博客,那是因为我想与大家分享.Net世界.我原来是ASP程序员,与.Net结缘那是在两年多前.第一次接触它,就喜欢上了.哈哈 接着我给大家分享一下我在项目中用到的数据访问层,这个是我用微软网站上得到的DBHepler数据库访问层的一次改编,让它支持实体类和用表达 式的方式生成SQL,而且更关键的是,他是采用参数的方式传值的,这样就避免了SQL的注入啦.. 以下是这个项目的结构 [SuperDAL] ---DbHelper.cs(来自MSDN的数据访问层) ---EntityManager.cs(实体类管理) ---Expressions.cs(实体类表达式查询) ---Expression.cs(实体类表达式) ---OrderByExpressions.cs(排序表达式查询) ---OrderByExpression.cs(排序表达式) ---ObjectValues -------OrderBy.cs(排序枚举类) ---DBManager.cs(数据访问类管理) ---DbParams.cs(数据库访问类参数) ---DataTableExtensions.cs(这个就是顾名思义啦,DataTable传实体类) 在这里最主要介绍的就是EntityManager这个啦,使用方法如下: 有数据库DB的一张表Customs CREATE TABLE [Customs] ( [Name] [varchar] (20) , [Password] [varchar] (20) , [Email] [varchar] (50) , [Phone] [varchar] (11) NULL , [Old] [int] , [Birthday] [DateTime] ) 有个实体类Customs.cs,结构如下: public class Customs { public string Name {get;set;} public string Password {get;set;} public string Email {get;set;} public string Phone {get;set;} public int Old{get;set} public DateTime Brithday {get;set;} } 数据库表与实体Customs结构是一一对应的.有了实体类CUstoms,下面就可以操作实体类跟操作数据库一样的啦,我们新建一个实体类管理类 CustomsManager.cs public class CustomsManager:EntityManager { public Customs GetByName(string name) { //创建表达式Expressions Expressions exps=new Expressions(); //向表达式添加条件 exps.Eq("name",name); //根据条件查询返回实体类 return EM_GetUnique(exps); } public List SearchByName(string name) { //同样像上面一样建立表达式类 Expressions exps=new Expressions(); exps.Like("name",name);//当然,有年朋友会说如果我要姓为"陈"的,那有些人的名字带陈的怎么办,没关系,可以改为 exps.LeftLike ("name",name); //根据条件查询返回实体类 return EM_GetEntity(exps); } /// /// 登录 /// /// 用户名 /// 密码 public List Login(string name,string password) { Expressions exps=new Expressions(); exps.Eq("name",name); exps.Eq("password",password); return EM_GetEntity(exps); } /// /// 选择年龄大于指定岁数的,并按年龄从小到大排序 /// /// 年龄 public List SelectOlder(int old) { Expressions exps=new Expressions(); exps.Gt("old",old); exp.OrderBys.Add("old", OrderBy.Asc); return EM_GetEntity(exps); } /// /// 选择年龄大于小于指定岁数段的,并按年龄从小到大,姓名从字母升序排序 /// /// 年龄 public List SelectByOld(int oldStart,int oldend) { Expressions exps=new Expressions(); exps.Between("old",oldStart,oldEnd); exp.OrderBys.Add("old", OrderBy.Asc); exp.OrderBys.Add("name",OrderBy.Asc); return EM_GetEntity(exps); } #region 增删改 操作 /// /// 更新操作 /// /// 实体类 public int Update(Customs customs) { return EM_Save(customs);//返回更新的记录数,当然,一般成功执行就会返回1;也可以改上面为public void Update(Customs customs) } /// /// 删除操作 /// /// public int DeleteByName(string name) { Expressions exps=new Expressions(); exps.Eq("name",name); return EM_Delete(exps); } /// /// 删除操作 /// /// 实体类 public int Save(Customs custom) { return EM_Save(custom); } #endregion } 当然还有更多的也就不一一贴出来了 Expressions支持的表达式有 1. Eq (等于)[name=value] 2. NotEq (不等于)[not name = value] 3. Ge (大于等于)[name >=value] 4. Gt (大于)[name>value] 5. Le (小于等于)[name<=value] 6. Lt (小于)[name<value] 7. In (包括)[name in (value)] 8. NotIn (不包括)[not name in (value) 9. IsNotNull (不为NULL)[not name is null] 10. IsNull (等于NULL)[name is null] 11. Between (之间)[name between valueStart and valueEnd] 12. Like (模糊) [name like ‘%value%’ ] 13. LeftLike (左模糊) [name like ‘%value’] 14. RightLike (右模糊) [name like ‘value%’] 其它功能待与Net爱好者探讨啦,希望你有更好的思路
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值