Spring Boot+JPA+Mysql完成数据库整合操作
来源:互联网 发布:学科竞赛本科状态数据 编辑:程序博客网 时间:2024/05/21 11:10
Spring Boot结合JPA操作Mysql数据库十分方便,可以做到零配置文件。具体流程如下。
一、Maven依赖
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>springboot.example</groupId> <artifactId>springboot-mysql</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- springboot操作数据库依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- mysql连接驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- 测试 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies></project>
二、实体类
本次测试一共设置了三个实体类,分别是User(用户)、Role(角色)、Department(部门)。三者之间的关系是:一个用户可以拥有多个角色,也就是用户和角色之间是一对多的关系,一个用户只属于一个部门,一个部门可以拥有多个用户,也就是说用户和部门之间是多对一的关系。
User.java
package com.lemon.springboot.domain;import com.fasterxml.jackson.annotation.JsonBackReference;import org.springframework.format.annotation.DateTimeFormat;import javax.persistence.*;import java.io.Serializable;import java.util.Date;import java.util.List;/** * @author lemon */@Entity@Table(name = "user")public class User implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name", length = 20) private String name; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Column(name = "createTime") private Date createDate; @ManyToOne @JoinColumn(name = "did") // 防止递归访问 @JsonBackReference private Department department; @ManyToMany(cascade = {}, fetch = FetchType.EAGER) @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")}) private List<Role> roles; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", createDate=" + createDate + ", department=" + department + ", roles=" + roles + '}'; }}Role.java
package com.lemon.springboot.domain;import javax.persistence.*;import java.io.Serializable;/** * @author lemon */@Entity@Table(name = "role")public class Role implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name", length = 20) private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Role{" + "id=" + id + ", name='" + name + '\'' + '}'; }}Department.java
package com.lemon.springboot.domain;import javax.persistence.*;import java.io.Serializable;/** * @author lemon */@Entity@Table(name = "department")public class Department implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name", length = 20) private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Department{" + "id=" + id + ", name='" + name + '\'' + '}'; }}
三、DAO层
DAO层采用的是Spring Data JPA,这个操作数据库十分方便。
- Repository (空接口)
- CrudRepository (增删改查)
- PagingAndSortingRepository (分页和排序)
- JpaRepository (扩展增删改查、批量操作 )
- JpaSpecificationExecutor: 用来做负责查询的接口
- Specification:是Spring Data JPA提供的一个查询规范, 要做复杂的查询,类似hibernate QBC查询
Spring Data JPA的使用十分简单,只需要我们编写DAO接口来继承上述的接口即可,不需要编写这个接口的实现类,然后我们在Service层注入编写的接口即可。在这里我们一般都是直接继承JpaRepository这个接口。因为上述的前四个接口存在着一层一层的继承关系,我们的接口继承了JpaRepository,也就具备了它的父接口所有的方法。
如果持久层接口较多,且每一个接口都需要声明相似的增删改查方法,直接继承 Repository 就显得有些啰嗦,这时可以继承 CrudRepository,它会自动为域对象创建增删改查方法,供业务层直接使用。开发者只是多写了 "Crud" 四个字母,即刻便为域对象提供了开箱即用的十个增删改查方法。
但是,使用 CrudRepository 也有副作用,它可能暴露了你不希望暴露给业务层的方法。比如某些接口你只希望提供增加的操作而不希望提供删除的方法。针对这种情况,开发者只能退回到 Repository 接口,然后到 CrudRepository 中把希望保留的方法声明复制到自定义的接口中即可(体现了强大的灵活性)。
分页查询和排序是持久层常用的功能,Spring Data 为此提供了 PagingAndSortingRepository 接口,它继承自 CrudRepository 接口,在 CrudRepository 基础上新增了两个与分页有关的方法。但是,我们很少会将自定义的持久层接口直接继承自 PagingAndSortingRepository,而是在继承 Repository 或 CrudRepository 的基础上,在自己声明的方法参数列表最后增加一个 Pageable 或 Sort 类型的参数,用于指定分页或排序信息即可,这比直接使用 PagingAndSortingRepository 提供了更大的灵活性。
JpaRepository 是继承自 PagingAndSortingRepository 的针对 JPA 技术提供的接口,它在父接口的基础上,提供了其他一些方法,比如 flush(),saveAndFlush(),deleteInBatch() 等。如果有这样的需求,则可以继承该接口。
上述四个接口,开发者到底该如何选择?其实依据很简单,根据具体的业务需求,选择其中之一。下面写出三个Repository。
UserRepository.java
package com.lemon.springboot.repository;import com.lemon.springboot.domain.User;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;/** * @author lemon */@Repositorypublic interface UserRepository extends JpaRepository<User, Long> {}
RoleRepository.java
package com.lemon.springboot.repository;import com.lemon.springboot.domain.Role;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;/** * @author lemon */@Repositorypublic interface RoleRepository extends JpaRepository<Role, Long> {}
DepartmentRepository.java
package com.lemon.springboot.repository;import com.lemon.springboot.domain.Department;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;/** * @author lemon */@Repositorypublic interface DepartmentRepository extends JpaRepository<Department, Long> {}
四、JPA配置类(重要)
这个配置类代替了传统的配置文件模式,配置信息都写在这个配置类中。
package com.lemon.springboot.configuration;import org.springframework.boot.autoconfigure.domain.EntityScan;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;import org.springframework.data.jpa.repository.config.EnableJpaRepositories;import org.springframework.jdbc.datasource.DriverManagerDataSource;import org.springframework.orm.jpa.JpaTransactionManager;import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;import org.springframework.orm.jpa.vendor.Database;import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;import org.springframework.transaction.PlatformTransactionManager;import org.springframework.transaction.annotation.EnableTransactionManagement;import org.springframework.transaction.support.TransactionTemplate;import javax.sql.DataSource;import java.util.Properties;/** * JPA配置类 * * @author lemon */@Order(Ordered.HIGHEST_PRECEDENCE)@Configuration@EnableTransactionManagement(proxyTargetClass = true)@EnableJpaRepositories(basePackages = "com.lemon.springboot.repository")@EntityScan(basePackages = "com.lemon.springboot.domain")public class JpaConfiguration { @Bean PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() { return new PersistenceExceptionTranslationPostProcessor(); } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://192.168.25.133:3306/springboot?characterEncoding=utf8"); dataSource.setUsername("root"); dataSource.setPassword("root"); return dataSource; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource()); entityManagerFactoryBean.setPackagesToScan("com.lemon.springboot.domain"); entityManagerFactoryBean.setJpaProperties(buildHibernateProperties()); entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter() {{ setDatabase(Database.MYSQL); }}); return entityManagerFactoryBean; } protected Properties buildHibernateProperties() { Properties hibernateProperties = new Properties(); hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"); hibernateProperties.setProperty("hibernate.show_sql", "true"); hibernateProperties.setProperty("hibernate.use_sql_comments", "false"); hibernateProperties.setProperty("hibernate.format_sql", "true"); hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update"); hibernateProperties.setProperty("hibernate.generate_statistics", "false"); hibernateProperties.setProperty("javax.persistence.validation.mode", "none"); //Audit History flags hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", "true"); hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", "true"); return hibernateProperties; } @Bean public PlatformTransactionManager transactionManager() { return new JpaTransactionManager(); } @Bean public TransactionTemplate transactionTemplate() { return new TransactionTemplate(transactionManager()); }}
五、测试
package com.lemon.springboot.test;import com.lemon.springboot.configuration.JpaConfiguration;import com.lemon.springboot.domain.Department;import com.lemon.springboot.domain.Role;import com.lemon.springboot.domain.User;import com.lemon.springboot.repository.DepartmentRepository;import com.lemon.springboot.repository.RoleRepository;import com.lemon.springboot.repository.UserRepository;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import org.springframework.util.Assert;import java.util.Date;import java.util.List;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = {JpaConfiguration.class})public class SpringBootMysqlTest { private static Logger logger = LoggerFactory.getLogger(SpringBootMysqlTest.class); @Autowired private UserRepository userRepository; @Autowired private DepartmentRepository departmentRepository; @Autowired private RoleRepository roleRepository; /** * 初始化数据 */ @Before public void init() { // 删除数据库所有数据 userRepository.deleteAll(); departmentRepository.deleteAll(); roleRepository.deleteAll(); // 向部门添加数据 Department department = new Department(); department.setName("开发部"); departmentRepository.save(department); Assert.notNull(department.getId(), "主键生成失败"); // 向角色添加数据 Role role = new Role(); role.setName("admin"); roleRepository.save(role); Assert.notNull(role.getId(), "主键生成失败"); // 向用户添加数据 User user = new User(); user.setName("user"); user.setCreateDate(new Date()); user.setDepartment(department); List<Role> roles = roleRepository.findAll(); Assert.notNull(role, "roles为空"); user.setRoles(roles); userRepository.save(user); Assert.notNull(user.getId(), "主键生成失败"); } @Test public void findPage() { Pageable pageData = new PageRequest(0, 10, new Sort(Sort.Direction.ASC, "id")); Page<User> page = userRepository.findAll(pageData); Assert.notNull(page, "未查询到数据"); for (User user : page.getContent()) { logger.info("=====user===== user name:{}, department name:{}, role name:{}", user.getName(), user.getDepartment().getName(), user.getRoles().get(0).getName()); } }}运行上面的测试方法,就可以对数据库进行操作了。代码托管在码云,可以下载。
- Spring Boot+JPA+Mysql完成数据库整合操作
- Spring boot结合Spring-Data-JPA操作MySQL数据库
- Spring Boot 添加MySQL数据库及JPA
- spring boot-jpa整合QueryDSL来简化复杂操作
- spring-boot(二) 整合jpa
- Spring Boot Mysql 数据库操作
- Spring boot操作mysql数据库
- 基于Spring boot的Spring data jpa连接MySQL数据库
- spring boot 整合 spring data jpa
- spring boot 整合spring data jpa
- spring boot 整合spring data jpa
- Spring Boot 学习第二步 配置MySQL数据库+JPA
- Spring Boot 学习第二步 配置MySQL数据库+JPA
- Spring Boot 学习第二步 配置MySQL数据库+JPA
- spring boot jpa update 操作
- Spring boot JPA 常用操作
- Spring Boot JPA 连接数据库
- Spring Boot JPA 连接数据库
- Java数据结构与算法解析——优先级队列
- Activity A 跳转到 Activity B,生命周期的执行过程
- MyBatis中如何通过继承SqlSessionDaoSupport来编写DAO
- 深入解析Java中的深拷贝和浅拷贝
- jvm的基本结构
- Spring Boot+JPA+Mysql完成数据库整合操作
- 数组(七)--折半查找
- 二叉树的镜像
- SpringAOP实例之简单实现(Annotation形式)
- 并发编程修炼八:Java ConcurrentModificationException异常原因和解决方法
- 微信开发-公众号支付(1)-获取openid
- Jenkins + svn 构建项目
- 设计模式学习总结:策略模式(Strategy Pattern)
- app与网页交互