栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springboot + JPA

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springboot + JPA

关于ORM框架(Object Relational Mapping 对象关系映射),mybatis 与 JPA各有各的好,都实现了对DAO层(Data Access Object 数据访问对象)功能的强大封装。mybatis可以灵活地手写各种复杂的SQL, 性能也更好;JPA对于扩展实体对象属性字段更友好。

个人建议:追求短平快的小公司可以采用JPA,开发更高效;业务繁杂的大中型企业宜采用mybatis,追求性能与稳定。

JPA(Java Persistence API),(插句题外话:看到一些缩写词,我习惯找出他的全称,有助于理解相关技术的灵魂。)顾名思义就是Java 持久层API,确切地说JPA不是一个技术框架,而是一种接口规范标准,大多习惯用Hibernate框架来实现。

有关springboot的快速搭建配置,请回看历史分享springboot+mybatis。

springboot集成各种功能组件大多采用三步走,一般步骤不外乎:

  1. 依赖 - maven pom文件追加相关依赖
  2. 配置 - yml 文件追加相关配置 或 自定义配置
  3. 封装 - 根据架构设计组装自己的通用组件(工具)

接下来按部就班单刀直入JPA(假定springboot脚手架已搭建好且运行正常)。

1. maven添加JPA依赖

数据源依赖,同mybatis


    org.springframework.data
    spring-data-jpa


    org.hibernate
    hibernate-core


    org.hibernate.javax.persistence
    hibernate-jpa-2.1-api
    1.0.0.Final


    org.hibernate
    hibernate-validator
    5.4.2.Final
2. JPA 配置

1.yml(数据源配置,同mybatis)

spring:
  #jpa
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
      naming:
        physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
    properties:
      hibernate:
        format_sql: false
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect # 默认使用innodb存储引擎

2.application(实体类及Repository扫描)

@EntityScan(basePackages = {"com.example.demo.domain"})
@EnableJpaRepositories(basePackages = {"com.example.demo.repository"})
@SpringBootApplication
public class DemoApplication{
  public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
3. JPA 功能封装

1) entity

Domain

import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

@Slf4j
@Data
@MappedSuperclass // 该注解作用:该父类不对应映射数据库中的表,但属性可以被子类继承
public class Domain implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Integer id;

    @Column(columnDefinition = "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'")
    protected Date createTime;

    @Column(columnDefinition = "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间'")
    protected Date updateTime;

    @JSonField(serialize = false)
    @Column(columnDefinition = "TINYINT(2) NOT NULL DEFAULT 0 COMMENT '删除标志'")
    protected Byte delFlag;

}

User

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@EqualsAndHashCode(callSuper = true)
@Data
@Entity
@Table(name = "user_user")
@DynamicInsert
@DynamicUpdate
public class User extends Domain {

    @Column(columnDefinition = "VARCHAr(28) NOT NULL DEFAULT '' COMMENT '注册手机号或微信openId'")
    private String account;

    @Column(columnDefinition = "VARCHAr(32) NOT NULL DEFAULT '' COMMENT '注册登录密码'")
    private String password;
}

2) repository

import com.example.demo.domain.Domain;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

public interface baseRepository extends JpaSpecificationExecutor, JpaRepository {

    default Specification getSpecification(S example) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            Path id = root.get("id");
            Path delFlag = root.get("delFlag");

            List predicateList = new ArrayList<>();

            if (example.getId() != null && example.getId() > 0) {
                predicateList.add(criteriaBuilder.equal(id, example.getId()));
            }
            if (example.getDelFlag() != null) {
                predicateList.add(criteriaBuilder.equal(delFlag, example.getDelFlag()));
            }

            return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));
        };
    }

}
import com.example.demo.domain.User;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

public interface UserRepository extends baseRepository {

    default Specification getSpecification(User example) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            Path id = root.get("id");
            Path account = root.get("account");
            Path delFlag = root.get("delFlag");

            List predicateList = new ArrayList<>();

            if (example.getId() != null && example.getId() > 0) {
                predicateList.add(criteriaBuilder.equal(id, example.getId()));
            }
            if (example.getDelFlag() != null) {
                predicateList.add(criteriaBuilder.equal(delFlag, example.getDelFlag()));
            }
            if (!StringUtils.isEmpty(example.getAccount())) {
                predicateList.add(criteriaBuilder.equal(account, example.getAccount()));
            }

            return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));
        };
    }

    User findByAccount(String account);

    // native SQL
    @Query(value = "select u.* from user_user u where u.id = ?1 or u.account = ?2 ", nativeQuery = true)
    User queryUser(Integer id, String account);

    // JPQL
    @Modifying // 更新或删除时需要加此注解,查询时不需要
    @Query("update User set account = :account where id = :id ")
    User updateUserAccount(@Param("id") Integer id, @Param("account") String account);
}

3) service

baseService:

import com.example.demo.po.PagerRequest;
import org.springframework.data.domain.Page;

import java.util.List;

public interface baseService {

    
    T merge(T domain);

    
    List mergeAll(Iterable domains);

    
    void delete(T domain);

    
    void deleteAll(Iterable domains);

    
    T findById(Integer id);

    
    List findAllById(Iterable ids);

    
    List findByExample(T domain);

    
    long count(T domain);

    
    Page findByPage(PagerRequest pagerRequest);

}
import com.example.demo.domain.Domain;
import com.example.demo.po.PagerRequest;
import com.example.demo.repository.baseRepository;
import com.example.demo.service.baseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.List;

@Slf4j
public abstract class baseServiceImpl implements baseService {

    @Autowired
    private baseRepository baseRepository;

    private Class domain;

    public baseServiceImpl() {
        ParameterizedType parameterizedType = ((ParameterizedType) getClass().getGenericSuperclass());
        domain = (Class) parameterizedType.getActualTypeArguments()[0];
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public T merge(T domain) {
        return baseRepository.save(domain);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List mergeAll(Iterable domains) {
        return baseRepository.saveAll(domains);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(T domain) {
        baseRepository.delete(domain);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteAll(Iterable domains) {
        baseRepository.deleteAll(domains);
    }

    @Override
    public T findById(Integer id) {
        if(id != null && id > 0){
            return baseRepository.findById(id).orElse(null);
        }
        return null;
    }

    @Override
    public List findAllById(Iterable ids) {
        if(ids != null){
            return baseRepository.findAllById(ids);
        }
        return Collections.emptyList();
    }

    @Override
    public List findByExample(T domain) {
        return baseRepository.findAll(baseRepository.getSpecification(domain));
    }

    @Override
    public long count(T domain) {
        return baseRepository.count(baseRepository.getSpecification(domain));
    }

    @Override
    public Page findByPage(PagerRequest pagerRequest) {
        try {
            T t = domain.newInstance();

            // 查询参数封装转换 (如分页查询User, 创建UserRequest extends PagerRequest,
            BeanUtils.copyProperties(pagerRequest, t);

            // 排序处理
            Sort sort = pagerRequest.getSort();
            if (sort == null) {
                sort = new Sort(Sort.Direction.DESC, "id");
            }

            // JPA分页从0开始, mybatis pagerHelper从1开始
            PageRequest pageable = PageRequest.of((pagerRequest.getPageNum() - 1), pagerRequest.getPageSize(), sort);
            // 在对应的repository中覆写getSpecification方法
            return baseRepository.findAll(baseRepository.getSpecification(t), pageable);
        } catch (Exception e) {
            log.error("异常信息:{}", e.getMessage());
            throw new RuntimeException("查询参数异常");
        }
    }

}

UserService:

import com.example.demo.domain.User;

public interface UserService extends baseService {

    
    User findByAccount(String account);

    User queryUser(Integer id, String account);

    User updateUserAccount(Integer id, String account);
}
import com.example.demo.domain.User;
import com.example.demo.repository.UserRepository;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends baseServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public  User findByAccount(String account) {
        return userRepository.findByAccount(account);
    }
  
    @Override
    public User queryUser(Integer id, String account) {
        return userRepository.queryUser(id, account);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public User updateUserAccount(Integer id, String account) {
        return userRepository.updateUserAccount(id, account);
    }

}

写在最后:ORM一般作为关系型数据库的持久层处理解决方案,对于非关系型数据库(也就是我们常说的NoSQL), 比如:redis, mongoDB, ES, solr等(虽然有些侧重搜索,但也都具有数据存储功能),spring也可以无缝集成,下次聊聊springboot + springdata,其实JPA也是基于springdata。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号