Spring Boot 使用JPA(Hibernate)操作数据库

版权声明:From Lay https://blog.csdn.net/Sadlay/article/details/83717195

使用JPA(Hibernate)操作数据库

JAP(Java Persisitence API),定义了对象关系映射(ORM)以及实体对象持久化的标准接口。

概述

在spring boot中JPA是依靠Hibernate才得以实现的。

JPA所维护的核心是实体(Entity Bean),而它是通过一个持久化上下文(Persinstence Context)来使用的。持久化上下文包含以下3个部分:

  • 对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R映射)描述,JPA支持注解或者XML两种形式的描述,在spring boot中主要通过注解实现。
  • 实体操作API,通过规范可以实现对实体对象的CRUD操作,来完成对象的持久化和查询。
  • 查询语言,约定了面向对象的查询语言JPQL(Java Persistence Query Language),通过这层关系可以实现比较灵活的查询。

开发JPA

在Maven中引入spring-boot-starter-data-jpa

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

定义用户POJO

package com.lay.pojo;

//指明User是一个实体
@Entity(name = "user")
//定义映射的表
@Table(name = "t_user")
public class User {
    //表明主键
    @Id
    //策略为递增
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id = null;
    
    //定义属性和表的映射关系(属性和数据库列名不一致)
    @Column(name = "user_name")
    private String userName = null;
    
    //定义转换器
    @Convert(converter = SexConverter.class)
    private SexEnum sex = null;//枚举
    
    private String note = null;
    
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getUserName() {
        return userName;
    }
    
    public void setUserName(String userName) {
        this.userName = userName;
    }
    
    public SexEnum getSex() {
        return sex;
    }
    
    public void setSex(SexEnum sex) {
        this.sex = sex;
    }
    
    public String getNote() {
        return note;
    }
    
    public void setNote(String note) {
        this.note = note;
    }
    
}

性别枚举类SexEnum

package com.lay.enumeration;

public enum SexEnum {
    MALE(1, "男"), FEMALE(2, "女");
    
    private int id;
    
    private String name;
    
    SexEnum(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
    public static SexEnum getEnumById(int id) {
        for (SexEnum sex : SexEnum.values()) {
            if (sex.getId() == id) {
                return sex;
            }
        }
        return null;
    }
    
    public static SexEnum getEnumByName(String name) {
        for (SexEnum sex : SexEnum.values()) {
            if (sex.getName().equals(name)) {
                return sex;
            }
        }
        return null;
    }
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
}

性别转换器SexConverter

package com.lay.converter;


public class SexConverter implements AttributeConverter<SexEnum, Integer> {
    
    //将枚举转换为数据库列
    @Override
    public Integer convertToDatabaseColumn(SexEnum sex) {
        return sex.getId();
    }
    
    //將数据库列转换为枚举
    @Override
    public SexEnum convertToEntityAttribute(Integer id) {
        return SexEnum.getEnumById(id);
    }
    
}

JPA接口

有了上述POJO对象的定义,我们还需要一个JPA接口来定义对应的操作。为此Spring提供了JpaRepository接口,它本身也继承了其他接口。

JPA最顶级的接口是Repsitory,而它没有定义任何方法,定义方法的是它的子接口CrudRepository,其定义的最基本的增删改查操作,功能性还不足够强大。为此PagingAndSortingRepository则继承了它并且提供了分页和排序的功能,最后JpaRepository扩展了PagingAndSortingRepository,而且还有QueryByExampleExecutor接口,这样就可以拥有按例子(Example)查询的功能,一般而言。我们只需要定义JPA扩展接口JpaRepository便可以获得JPA提供的方法了。

JpaUserRepository

package com.lay.dao;


public interface JpaUserRepository extends JpaRepository<User, Long> {
    
}

这样便拥有了系统默认帮我们实现的方法。请注意,这并不需要提供任何实现类,这些spring会根据JPA接口规范帮我们完成。

接口扫描和实体注册

对于Jpa接口JpaUserRepository,还需要制定Spring boot的扫描路径,才能将接口扫描到spring ioc容器中。与此同时,我们还要将实体类User的注册给JPA才能测试这个控制器。用到两个JPA注解:

  • @EnableJpaRepositories:启用JPA编程
  • @EntityScan:对实体Bean扫描

启动主函数SpringbootDatabaseApplication

package com.lay;

@SpringBootApplication
//定义JPA接口扫描包路径
@EnableJpaRepositories(basePackages = "com.lay.dao")
//定义实体Bean扫描包路径
@EntityScan(basePackages = "com.lay.pojo")
public class SpringbootDatabaseApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(SpringbootDatabaseApplication.class, args);
    }
}

实际上,即使没有使用@EnableJpaRepositories和@EntityScan,只要依赖了spring-boot-starter-jpa。spring boot2.x也会对项目进行扫描。

扫描二维码关注公众号,回复: 3935429 查看本文章

配置文件

application.properties

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot_database
spring.datasource.username=root
spring.datasource.password=123456
# spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#指定数据连接池的类型
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
#最大等待连接中的数量,设置0为没有限
spring.datasource.dbcp2.max-idle=10
#最大连接活动数
spring.datasource.dbcp2.max-total=50
#最大等待毫秒数,单位ms,超过时间会出错误信息
spring.datasource.dbcp2.max-wait-millis=10000
#数据库连接池初始化连接数
spring.datasource.dbcp2.initial-size=5

#使用MySQL数据库方言
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
#打印数据库sql
spring.jpa.show-sql=true
#选择hibernate数据定义语言(DDL)策略为update
spring.jpa.hibernate.ddl-auto=update

控制器测试接口

JpaController

package com.lay.controller;

@Controller
@RequestMapping(value = "/jpa")
public class JpaController {
    
    //注入JPA接口
    @Autowired
    private JpaUserRepository jpaUserRepository = null;
    
    @RequestMapping("/getUser")
    @ResponseBody
    public User getUser(Long id) {
        //使用JPA接口查询对象
        User user = jpaUserRepository.findById(id).get();
        return user;
        
    }
}

启动服务测试,在浏览器地址栏输入http://localhost:8080/jpa/getUser?id=1

日志打印了sql

Hibernate: select user0_.id as id1_0_0_, user0_.note as note2_0_0_, user0_.sex as sex3_0_0_, user0_.user_name as user_nam4_0_0_ from t_user user0_ where user0_.id=?

使用JPA查询语言JPQL

JPA查询语言JPQL与Hibernate提供的HQL是十分接近的。这里使用注解@Query标识语句就可以了。

JpaUserRepository

package com.lay.dao;

public interface JpaUserRepository extends JpaRepository<User, Long> {
    
    @Query("form user where user_name like concat('%',?1,'%')" + "and note like concat('%',?2,'%')")
    public List<User> findUsers(String userName, String note);
}

注意这里写from user中的user是定义实体类名称(@Entity注解的name属性),所以才能这样定义一条JPQL,提供给上层调用。

JPA命名查询

除了可以定义语句查询,按照一定规则命名的方法也可以在不写任何代码的情况下完成逻辑。

package com.lay.dao;

import java.util.List;

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

import com.lay.pojo.User;

public interface JpaUserRepository extends JpaRepository<User, Long> {
    
    @Query("form user where user_name like concat('%',?1,'%')" + "and note like concat('%',?2,'%')")
    public List<User> findUsers(String userName, String note);
    
    /**
     * 按用户名称模糊查询
     * @param userName
     * @return
     * @Date        2018年10月29日 下午4:58:07 
     * @Author      lay
     */
    List<User> findByUserNameLike(String userName);
    
    /**
     * 根据主键查询
     * @param id
     * @return
     * @Date        2018年10月29日 下午4:58:45 
     * @Author      lay
     */
    User getUserById(Long id);
    
    /**
     * 按照用户名称或者备注进行模糊查询
     * @param userName
     * @param note
     * @return
     * @Date        2018年10月29日 下午4:59:57 
     * @Author      lay
     */
    List<User> findByUserNameLikeOrNoteLike(String userName, String note);
}

这里的命名是以动词(get/find)开始的,而已by代表按照什么内容进行查询。

猜你喜欢

转载自blog.csdn.net/Sadlay/article/details/83717195