深入浅出springboot2.x(9)使用JPA操作数据库

使用JPA操作数据库

创建表sql:

CREATE TABLE `t_user` (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(60) NOT NULL,
  `sex` int(3) NOT NULL DEFAULT '1' check (sex in(1,2)),
  `note` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

在maven中引入spring-boot-starter-data-jpa,接着创建pojo与表对应起来:

package com.example.JPAdemo;
//import org.springframework.data.annotation.Id;
import javax.persistence.*;

@Entity(name="user")
@Table(name = "t_user")
public class User {
    @Id//主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)//主键策略,递增
    private int id;
    @Column(name = "user_name")
    private String userName;
    @Convert(converter = SexConverter.class)
    private SexEnum sex;
    private String note;
    *****getter and setter *****
}

使用@Entity标明这是一个实体类,@Table配置的属性name指出它映射数据库的表,这样实体就映射到了对应的表上,@Id标注那个属性为表的主键,@GeneratedValue则是可以配置采用何种策略生成主键,@Column标注用户名,因为属性名称(userName)和数据库列名(user_name)不一致,而其他属性名称和数据库列名保持一致,这样就能与数据库表字段一一对应起来了。这里的性别需要转换,使用@Convert指定了SexConverter作为转换器,SexConverter代码:

package com.example.JPAdemo;

import javax.persistence.AttributeConverter;

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

SexEnum代码:

package com.example.JPAdemo;

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 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定义了从数据库读出的转换规则和从属性转换为数据库列的规则,这样就能使性别枚举类与数据库的列对应起来。
有了pojo对象,我们还需要一个jpa接口来定义对应的操作。spring提供了JpaRepository接口提供,它本身继承了其他接口。JPA最顶级的接口是Repository,而它没有定义任何方法,定义方法是它的子接口CrudRepository,实现最基本的增删改操作,功能还不够强大,PagingAndSortingRepository则继承了它并且提供分页和排序功能,最后JpaRepository扩展了PagingAndSortingRepository,并且扩展了QueryByExampleExecutor接口,这样就有按例子查询的功能。一般而言,我们只需要定义JPA借口扩展JpaRepository便可以获得JPA提供的方法了。
定义JPA接口:

package com.example.JPAdemo;
import org.springframework.data.jpa.repository.JpaRepository;

public interface JpaUserRepository extends JpaRepository {
}

这样便拥有了系统默认帮我们实现的方法。这里并不需要提供任何实现类,这些spring会根据JPA接口规范帮我们完成,然后就可以开发控制器——JpaController:

package com.example.JPAdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/jpa")
public class JpaController {
    @Autowired
    private JpaUserRepository jpaUserRepository;

    @RequestMapping("/getUser")
    @ResponseBody
    public User getUser(int id){
        //使用jpa接口查询对象
        User user = jpaUserRepository.findOne(id);
        return user;
    }
}

配置JPA属性:

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

spring boot启动文件:

package com.example.JPAdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@EnableJpaRepositories(basePackages = "com.example.JPAdemo")
@EntityScan(basePackages = "com.example.JPAdemo")
@SpringBootApplication
public class JpAdemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(JpAdemoApplication.class, args);
		System.out.println("启动成功");
	}
}

这里使用@EnableJpaRepositories启用JPA和制定扫描的包,这样spring就会将对应的JPA接口扫描进来,并且生成对应的bean,装配在IOC容器中,这样就可以在控制器上用 @Autowired进行依赖注入了。通过定义@EntityScan定义的包扫描,就可以扫描装在JPA的实体类了。而实际上就算没有@EntityScan和@EnableJpaRepositories,只要依赖了spring-boot-starter-data-jpa,spring boot2.x也会对项目进行扫描,这样JPA的实体和接口都会被扫描,只是使用它们可以更进一步配置JPA的相关信息而已。
到这一步我们的开发就完了,在数据库里添加一条测试数据
在这里插入图片描述
测试结果:
深入浅出springboot2.x(9)使用JPA操作数据库_第1张图片
从结果中可以看出控制器已经通过JPA接口查询到了数据,然后将其展现为json。

注意问题

如果运行中出现这样的报错信息:

Error creating bean with name ‘entityManagerFactory’ defined in class path resource 。。。。。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.example.JPAdemo.User
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:856) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
	at com.example.JPAdemo.JpAdemoApplication.main(JpAdemoApplication.java:14) [classes/:na]
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: com.example.JPAdemo.User
	at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:265) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
	at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:211) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
	at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:717) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
	at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:245) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:770) ~[hibernate-entitymanager-5.0.3.Final.jar:5.0.3.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:797) ~[hibernate-entitymanager-5.0.3.Final.jar:5.0.3.Final]
	at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362) ~[spring-orm-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
	... 16 common frames omitted

这个需要检查一下User实体类,看@Id引用的包是不是
import org.springframework.data.annotation.Id;把这个删了就OK了,@Id引用的应该是import javax.persistence.Id;

你可能感兴趣的:(深入浅出springboot2.x(9)使用JPA操作数据库)