开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
使用数据库是开发基本应用的基础,借助于开发框架我们已经不用编写原始的访问数据库的代码,也不用调用JDBC(Java Data Base Connectivity)或者连接池等诸如此类的被称作底层的代码,我们将在高级的层次上访问数据库。而Spring Boot更是突破了以前所有开发框架访问数据库的方法,在前所未有的更加高级的层次上访问数据库。因为Spring Boot饮食一个功能强大的资源库,为使用Spring Boot的开发者提供了更加简便的接口进行访问。
本文使用JPA(Java Persistence API)资源库来实现对MySQL数据库的操作。简单来说,JPA就是为POJO (Plain Ordinary Java Object)提供持久化的标准规范,即将Java的普通对象通过对象关系映射(Object-RElational Mapping, ORM)持久化到数据库中。
1、配置依赖
创建一个Spring Boot项目,并添加如下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2、实体建模
首先创建一些普通对象,用来与数据库的表建立映射关系,我们举RBAC来演示操作数据库,ER模型如下:
创建实体类:
Department.java
@Data
@Entity
@Table(name = "department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
Role.java
@Data
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
User.java
@Data
@Entity
@Table(name = "user")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime registerDate;
/**
* @JsonBackReference 用来防止关系对象的递归访问
*/
@ManyToOne
@JoinColumn(name = "department_id")
@JsonBackReference
private Department department;
@ManyToMany(cascade = {}, fetch = FetchType.EAGER)
@JoinTable(name = "use_role",
joinColumns = {@JoinColumn(name = "user_id")},
inverseJoinColumns = {@JoinColumn(name = "roles_id")})
private List<Role> roles;
}
3、实体持久化
通过实体的定义,实现了使用Java的普通对象(POJO)与数据库表建立映射关系(ORM),接下来使用JPA来实现持久化。
用户实体使用JPA进行持久化,它是一个接口,并继承于JPA资源库JpaRepository接口,使用注解@Repository将这个接口也定义为一个资源库,使它能被其他程序引用,并为其他程序提供存取数据库的功能。
public interface DepartmentRepository extends JpaRepository<Department, Long> {
}
public interface RoleRepository extends JpaRepository<Role, Long> {
}
public interface UserRepository extends JpaRepository<User, Long> {
}
上图是JapRepository接口继承首张,JapRepository继承于PagingAndSortingRepository,它提供了分页和排序的功能,PagingAndSortingRepository继承于CrudRepository,它提供了简单的增删查改的功能。因为定义的接口继承于JpaRepository,所以它传递性地继承了上面所有这些接口,并拥有这些接口的所有方法。这些接口提供的一些方法如下:
<S extends T> S save(S entity);<S extends T> Iterable<S> saveAll(Iterable<S> entities);Optional<T> findById(ID id);boolean existsById(ID id);Iterable<T> findAll();Iterable<T> findAllById(Iterable<ID> ids);long count();void deleteById(ID id);void delete(T entity);void deleteAllById(Iterable<? extends ID> ids);void deleteAll(Iterable<? extends T> entities);void deleteAll();List<T> findAll();List<T> findAll(Sort sort);List<T> findAllById(Iterable<ID> ids);<S extends T> List<S> saveAll(Iterable<S> entities);void flush();<S extends T> S saveAndFlush(S entity);<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);void deleteAllInBatch(Iterable<T> entities);void deleteAllByIdInBatch(Iterable<ID> ids);void deleteAllInBatch();T getReferenceById(ID id);<S extends T> List<S> findAll(Example<S> example);<S extends T> List<S> findAll(Example<S> example, Sort sort);
4、MySQL测试
首先,增加一个使用JPA的配置类,下面我们定义一个测试时使用的JPA配置类:
@Configuration
@EnableJpaRepositories(basePackages = "com.**.repository")
public class JpaConfig {
@Bean
PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan("com.**.entity");
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());
}
}
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {JpaConfig.class})
public class MySqlTest {
private static Logger log = LoggerFactory.getLogger(MySqlTest.class);
@Autowired
UserRepository userRepository;
@Autowired
DepartmentRepository departmentRepository;
@Autowired
RoleRepository roleRepository;
@Before
public void initData() {
userRepository.deleteAll();
roleRepository.deleteAll();
departmentRepository.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.setRegisterDate(LocalDateTime.now());
user.setDepartment(department);
List<Role> roles = roleRepository.findAll();
Assert.notNull(roles);
user.setRoles(roles);
userRepository.save(user);
Assert.notNull(user.getId());
}
@Test
public void test() {
System.out.println("hello world");
}
@Test
public void testFindPage() {
Pageable pageable = PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "id"));
Page<User> page = userRepository.findAll(pageable);
Assert.notNull(page);
System.out.println("size: " + page.getSize());
for (User user : page.getContent()) {
System.out.println("11111");
log.info("===user=== user name:{}, department name: {}, role name: {}",
user.getName(), user.getDepartment().getName(), user.getRoles().get(0).getName());
}
}
}