依赖
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- WEB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- ORACLE,直接导入不起作用,下jar文件打包成maven的坐标 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
配置文件
spring.datasource.url=jdbc:oracle:thin:@ip:port:orcl
spring.datasource.username=111
spring.datasource.password=111
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.jpa.hibernate.ddl-auto=create
#create每次都会重新创建数据库表,update有表不会重新创建会刷新字段,没有表会重新创建表。
spring.jpa.show-sql=true
#打印执行的SQl
实体
@Entity,作用在类上,表示与数据库的表(默认类名)映射。可以使用name指定表。
@Table,作用在类上,表示指定数据库的表,跟@Entity的name属性功能差不多。
@Id,作用在属性上,标识该属性是主键,与数据库表的主键对应。(一般都得写)
@Column,作用在属性上,标识该属性是普通属性与数据库表字段对应(默认属性名对应,属性名驼峰命名和表的字段下划线命名可以对应),可以用name属性指定与数据库表字段的对应。(属性名跟表的字段名对应可以不写)
Mysql主键生成策略:
@GeneratedValue():整形自增。
Oracle主键生成策略:
整形,序列的方式:
@GeneratedValue(generator = "sequenceGenerator")//随便写个主键策略名称
@GenericGenerator(
name = "sequenceGenerator", //与上边对应
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",//主键生成策略
parameters = {
@Parameter(name = "sequence_name", //传递参数(sequence_name表示创建序列)
value = "SEQ_CUSTOMER_ID")//序列名称,ddl为update或者create时自动创建
}
)
字符串主键,uuid的方式:
@GenericGenerator(name="sequeneceGenerator",strategy="uuid")
@GeneratedValue(generator="sequeneceGenerator")
表的联系,一对多:
* 1.声明关系
* @ManyToOne or @OneToMany
* targetEntity:对方字节码对象
* 2.配置外键
* @JoinColumn
* name:在多的一方生成数据库的外键名称
* referencedColumnName:自己表的主键名称(外键数据来源)
* 3.放弃外键维护
* mappedBy:去掉外键维护后应该指定与关联对象的属性名称
* 4.级联操作
* cascade:表示执行什么操作时,的级联操作
* 1.删除:删除所有关联对象
* 2.查找:查找关联对象
* ...
* 注意:一的那边放弃外键维护
一的实体配置:
@OneToMany(targetEntity=Order.class,mappedBy="customers",cascade=CascadeType.ALL)
private List<Order> orders;
多的实体配置:
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "customer_id", referencedColumnName = "id")
private Customer customers = new Customer();
持久层Repository
* JpaRepository<实体类名称,主键类型>
* 继承JpaRepository这个接口,这个类已经放到spring容器中了。
* JpaRepository内置了数据库表的操作函数
public interface CustomerRepository extends JpaRepository<Customer, Long> {
* 自定义sql语句
* nativeQuery=true,开启原生sql查询
* Paramz指定参数名称
* @Modifying 允许修改(增删改要加)
* @Transactional开启事务,注意是org.springframework.transaction.annotation.Transactional
@Query(value="select l.id,l.age,l.create_time,l.name from L_TEST l where l.age>:age",nativeQuery=true)
List<Customer> findByMinAge(@Param("age")Integer age);
}
服务层ServiceImpl
第一步:加个@Service把类放到spring容器中去。
介绍持久层的函数。
save(entity):保存或者更新一个对象,当entity没有主键时新增数据并且将数据库自增的主键返回到entity中,有主键时更新数据。
deleteById(id):根据id删除一条数据,id不存在抛出异常。
findById(id):根据id查找数据,数据库id不存在跑出异常。一般用法:
* 表示根据id查找数据,查不到返回null。
Order order = orderRepository.findById(id).orElse(null);
findAll():查全部。
JPA的语法规则
JPA会根据函数的名称去执行特定的语法规则,非常的方便快捷。
1.按实体的字段查询(注意驼峰)
findBy(第一个条件)And(第二个条件)***
* 查询指定年龄的用户
List<User> findByAge(String age);
* 查询指定年龄和指定名称的用户
List<User> findByAgeAndName(String age,String name);
2.in条件查询
findBy(条件)In
* 查询用户id在ids中的用户
List<User> findByIdsIn(List<String> ids);
* 查询用户id在ids中并且指定名称的用户
List<User> findByIdsInAndUserName(List<String> ids,String name);
JPA过滤查询
实体:
@Entity
@Table(name = "T_ARTICLE")
public class Article {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
private String id;
private String code;
private Timestamp createTime;
private Boolean flag;
@OneToOne(optional=true)
@JoinColumn(name="school_id", unique=false, nullable=true, updatable=true)
private School school;
}
持久层:
public interface ArticleRepository extends JpaRepository<Article, String>, JpaSpecificationExecutor<Article> {
}
构造过滤条件:
public Specification<Article> getSpecificationByParams(String id,String code,Timestamp createTime,Boolean flag){
return new Specification<Article>() {
private static final long serialVersionUID = 1L;
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//去重查询
query.distinct(true);
List<Predicate> predicates = new ArrayList<Predicate>();
//or条件空值判断
predicates.add(cb.or(cb.isFalse(root.<Boolean>get("flag")),cb.isNull(root.get("delFlag"))));
//等值判断
if(null != code&& !"".equals(code)) {
predicates.add(cb.equal(root.<String>get("code"), code));
}
//or 条件
if(null != code && !"".equals(code)) {
String[] codes = code.split("-");
List<Predicate> preOr = new ArrayList<Predicate>();
for (String c: codes) {
preOr.add(cb.equal(root.<String>get("c"), c));
}
Predicate[] pr = preOr.toArray(new Predicate[]{});
predicates.add(cb.or(pr));
}
//大于等于
if(null != startTime) {
predicates.add(cb.greaterThanOrEqualTo(root.<Timestamp>get("updateTime"), createTime));
}
//小于
if(null != endTime) {
predicates.add(cb.lessThanOrEqualTo(root.<Timestamp>get("updateTime"), createTime));
}
//模糊查询
if(null != code && !"".equals(code)) {
predicates.add(cb.like(root.<String>get("code"), "%"+code+"%"));
}
//多表关联
Subquery<String> articleSemiQ = getMagazineFavTypeSubquery.(query,cb,creditCode)
//若是配置对象
predicates.add(root.<Long> get("school").get("id").in(schoolId));
predicates.add(root.get("id").in(articleSemiQ));
//返回结果
return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
}
};
}
public Subquery<String> getMagazineFavTypeSubquery(CriteriaQuery<?> query, CriteriaBuilder cb, String code) {
//设置返回值类型
Subquery<String> semiQ = query.subquery(String.class);
//实体类
Root<Favoriten> semiRoot = semiQ.from(Favoriten.class);
//返回字段
semiQ.select(semiRoot.get("id"));
//设置过滤条件
List<Predicate> subQPredicates = new ArrayList<>();
subQPredicates.add(cb.equal(semiRoot.get("code"), code));
//返回值
semiQ.where(subQPredicates.toArray(new Predicate[subQPredicates.size()]));
return semiQ;
}
添加分页条件:
1.单个分页
PageRequest pageParam = PageRequest.of(pageNum,pageSize,Sort.by(Direction.DESC,"updateTime"));
2.多个分页
List<Order> sortlist = new ArrayList<>();
sortlist.add(new Order(Direction.DESC,"publishTime"));
sortlist.add(new Order(Direction.ASC, "typeId"));
sortlist.add(new Order(Direction.DESC, "issue"));
Sort sort = Sort.by(sortlist);
Pageable pageParam = PageRequest.of(pageNum, pageSize, sort);
查询结果:
Page<Article> articlePages = this.articleRepository.findAll(specification, pageParam);
调用存储过程
@PersistenceContext
private EntityManager em;
String a = "";
String b = "";
boolean result = true;
Query query = em.createNativeQuery("{call tmp_test(:p1,:p2)}");
query.setParameter("p1", a);
query.setParameter("p2", b);
query.executeUpdate();
原始SQL分页条件处理
(用问号占位符可以,用:参数名会报错?(之前设置了排序,他自己又内置排序所以出问题了暂时不知道这个占位符形式有什么问题))
Pageable pageable = new PageRequest(page, size);
@Query(value = "SELECT t1.* " +
"FROM T_ALARM t1 inner join T_COMMON_ALARM t2 on t1.COMMON_ALARM_ID = t2.ID AND t2.ALARM_TYPE_ID = :alarmTypeId " +
" inner join T_DISPOSAL_TYPE t3 on t1.disposal_type_id = t3.id " +
"WHERE t1.DISTRICT_ID IN :districtIds " +
"AND t3.CODE in :disposalTypeCodes " +
"AND t1.offhook_Time between :startTime and :endTime " +
"ORDER BY ?#{#pageable}",
countQuery = "SELECT count(1) " +
"FROM T_ALARM t1 inner join T_COMMON_ALARM t2 on t1.COMMON_ALARM_ID = t2.ID AND t2.ALARM_TYPE_ID = :alarmTypeId " +
" inner join T_DISPOSAL_TYPE t3 on t1.disposal_type_id = t3.id " +
"WHERE t1.DISTRICT_ID IN :districtIds " +
"AND t3.CODE in :disposalTypeCodes " +
"AND t1.offhook_Time between :startTime and :endTime " +
"ORDER BY ?#{#pageable}",nativeQuery = true)
Page<Alarm> findAlarmTypeTotal(@Param("alarmTypeId") Long alarmTypeId,
@Param("districtIds") Set<Long> districtIds,
@Param("startTime") Timestamp startTime,
@Param("endTime") Timestamp endTime,
@Param("disposalTypeCodes") Set<String> disposalTypeCodes,
Pageable pageable);
JPAlist为null的处理
"AND (:emergencyTypeIds is null or t3.ID IN :emergencyTypeIds) " +
//设置去重
public Predicate toPredicate(Root root, CriteriaQuery<?> query, CriteriaBuilder cb) {
query.distinct(true);
//分页查询 findAll(specification,pageable)需要JpaSpecificationExecutor
public interface AlarmFeedbackInfoRepository extends JpaRepository<AlarmFeedbackInfo,Long>, JpaSpecificationExecutor {
自定义主键
public class CustomizePrimaryKey extends UUIDGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor s, Object obj) throws HibernateException {
Serializable id = s.getEntityPersister(null, obj).getClassMetadata().getIdentifier(obj, s);
if (id != null && String.valueOf(id).length() > 0) {//新增时有id,则不自动生成id
return id;
} else {
return String.valueOf(super.generate(s, obj)).replace("-","");//替换掉uuid中间的“-”
}
}
}