SpringBoot整合JPA以及多数据源
springboot整合Jpa
1、基本配置:
①pom.xml配置:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.18</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.27</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
②yaml配置:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
jpa:
# 显示sql语句
show-sql: true
# 数据库
database: mysql
# 数据库平台
database-platform: mysql
# 设置表的结构的生成类型
hibernate:
# 每次启动更新表结构
ddl-auto: update
properties:
hibernate:
# 设置方言 mysql57
dialect: org.hibernate.dialect.MySQL57Dialect
③实体配置:
/**
* 指定表的名称 若不存在 则自动为你创建此表
*/
@Entity(name = "t_book")
@Getter
@Setter
@ToString
public class Book {
/**
*在jpa中一个表必须设置主键,否则创建会失败
* @Id标注的属性为主键
* @GeneratedValue指定生成策略为自增长
* @column中可设置字段的约束操作(长度为10)
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(length = 10)
private Integer id;
/**
* 设置自动不能为空,长度为50,设置数据库中和属性的对应名称
*/
@Column(nullable = false,length = 50,name = "name")
private String name;
/**
* 设置自动不能为空,长度为20,设置数据库中和属性的对应名称
*/
@Column(nullable = false,length = 20,name = "author")
private String author;
}
④jpa接口配置:
/**
* 这里要实现 JpaRepository 接口
* JpaRepository已经帮我们实现了很多操作直接使用即可
* 第一个参数为 操作的实体的类型
* 第二个参数为 主键的类型
*/
public interface BookDao extends JpaRepository<Book,Integer> {
}
⑤测试:
@SpringBootTest
class JpaApplicationTests {
@Autowired
private BookDao bookDao;
/**
* 增加
*/
@Test
void addBokk() {
Book book=new Book();
book.setName("西游记");
book.setAuthor("施耐庵");
bookDao.save(book);
}
/**
* 有则更新 无则添加
*/
@Test
void updateBook() {
Book book=new Book();
book.setName("xiyouji");
book.setAuthor("shinaian");
book.setId(1);
bookDao.saveAndFlush(book);
}
/**
* 通过id删除
*/
@Test
void deleteBook() {
bookDao.deleteById(1);
}
/**
* 通过id查询 查询所有
*/
@Test
void findBook() {
Optional<Book> byId = bookDao.findById(2);
System.out.println(byId.get());
List<Book> all = bookDao.findAll();
System.out.println(all);
}
/**
* 按照id 降序排序
*/
@Test
void findBookSort() {
List<Book> all = bookDao.findAll(Sort.by(Sort.Direction.DESC, "id"));
System.out.println(all);
}
/**
* 分页查询
*/
@Test
void findBookPage() {
//从第一页开始查询(起始为0),每页大小为2
Pageable pageable = PageRequest.of(2, 2);
Page<Book> all = bookDao.findAll(pageable);
System.out.println("总记录数:"+all.getTotalElements());
System.out.println("当前页记录数:"+all.getNumberOfElements());
System.out.println("每页记录数:" + all.getSize());
System.out.println("总页数:" + all.getTotalPages());
System.out.println("查询结果数据:" + all.getContent());
System.out.println("当前页数(从0开始):" + all.getNumber());
System.out.println("是否为首页:" + all.isFirst());
System.out.println("是否为尾页:" + all.isLast());
}
}
2、jpa使用关键字进行查询:
关键字查询参考表:
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1(parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1(parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1(parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection ages) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
①接口配置
/**
* 这里要实现 JpaRepository 接口
* JpaRepository已经帮我们实现了很多操作直接使用即可
* 第一个参数为 操作的实体的类型
* 第二个参数为 主键的类型
*/
public interface BookDao extends JpaRepository<Book,Integer> {
/**
* 根据id查找
* @param id
* @return
*/
Book findBookById(Integer id);
/**
* 查询比id小的
* @param integer
* @return
*/
List<Book> findBookByIdLessThan(Integer integer);
/**
* 查询比id大的或者包含此名称的
* @param id
* @param name
* @return
*/
List<Book> findBookByIdGreaterThanOrNameContaining(Integer id, String name);
}
②测试
@Test
void customeFind(){
Book bookById = bookDao.findBookById(4);
System.out.println(bookById);
List<Book> bookByIdLessThan = bookDao.findBookByIdLessThan(3);
System.out.println(bookByIdLessThan);
List<Book> finc = bookDao.findBookByIdGreaterThanOrNameContaining(6, "马");
System.out.println(finc);
}
3、jpa自定义sql查询
@Query
标记为自定义的sql查询,nativeQuery=true
,使用原生的sql操作
@Modifying
标记为更新删除或新增的方法
@Transactional
当方法为更新删除或者新增的时候,需要在自定义的方法上加上事务,或者在方法所在的dao或者service上加上事务@Transactional
两种传参形式:
① 冒号形式
Query(value = "insert into t_book(name,author) values(:name,:author)",nativeQuery = true)
Integer addBook(@Param("name")String name,@Param("author")String author);
② ?形式
@Modifying
@Transactional
@Query(value = "insert into t_book(name,author) values(?1,?2)",nativeQuery = true)
Integer addBook1(String name,String author);
/**
* 这里要实现 JpaRepository 接口
* JpaRepository已经帮我们实现了很多操作直接使用即可
* 第一个参数为 操作的实体的类型
* 第二个参数为 主键的类型
*/
public interface BookDao extends JpaRepository<Book,Integer> {
@Query(value = "select * from t_book where id=(select max(id) from t_book)",nativeQuery = true)
Book getMaxIdBook();
@Modifying
@Transactional
@Query(value = "insert into t_book(name,author) values(:name,:author)",nativeQuery = true)
Integer addBook(@Param("name")String name,@Param("author")String author);
@Modifying
@Transactional
@Query(value = "insert into t_book(name,author) values(?1,?2)",nativeQuery = true)
Integer addBook1(String name,String author);
}
4、多数据源配置
①pom.xml配置一致
②yaml配置
spring:
datasourceone:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
datasourcetwo:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://47.96.141.44:3306/test?useUnicode=true&characterEncoding=UTF-8
username: root
password: 147258369
jpa:
# 显示sql语句
show-sql: true
# 数据库
database: mysql
# 数据库平台
database-platform: mysql
# 设置表的结构的生成类型
hibernate:
# 每次启动更新表结构
ddl-auto: create
properties:
hibernate:
# 搜索mysql57即可 找到类路径
# 设置方言 mysql57
dialect: org.hibernate.dialect.MySQL57Dialect
③实体bean
/**
* 指定表的名称 若不存在 则自动为你创建此表
*/
@Entity(name = "t_book")
@Getter
@Setter
@ToString
public class Book {
/**
*在jpa中一个表必须设置主键,否则创建会失败
* @Id标注的属性为主键
* @GeneratedValue指定生成策略为自增长
* @column中可设置字段的约束操作(长度为10)
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(length = 10)
private Integer id;
/**
* 设置自动不能为空,长度为50,设置数据库中和属性的对应名称
*/
@Column(nullable = false,length = 50,name = "name")
private String name;
/**
* 设置自动不能为空,长度为20,设置数据库中和属性的对应名称
*/
@Column(nullable = false,length = 20,name = "author")
private String author;
}
④数据源注入
@Configuration
public class DataSourceConfig {
@Primary
@Bean
@ConfigurationProperties("spring.datasourceone")
DataSource dataSourceOne(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasourcetwo")
DataSource dataSourceTwo() {
return DruidDataSourceBuilder.create().build();
}
}
⑤事务及LocalContainerEntityManagerFactoryBean配置
/**
* basePackages 扫描所在接口的包
* entityManagerFactoryRef 引用配置的localContainerEntityManagerFactoryBeanOne
* transactionManagerRef 引用配置的 事务platformTransactionManagerOne
*/
@EnableJpaRepositories(basePackages = "org.lc.jpa.dao.dao1",entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanOne",transactionManagerRef = "platformTransactionManagerOne")
@Configuration
public class JpaConfigOne {
@Autowired
@Qualifier("dataSourceOne")
DataSource dataSourceOne;
//注入yaml中的其他属性配置
@Autowired
JpaProperties jpaProperties;
@Bean
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanOne(EntityManagerFactoryBuilder builder) {
//注入数据源
return builder.dataSource(dataSourceOne)
// 配置操作的实体bean
.packages("org.lc.jpa.bean")
// 注入配置属性文件
.properties(jpaProperties.getProperties())
// 初始化单元 不同即可
.persistenceUnit("pu1")
.build();
}
/**
* 事务的配置
* @param builder
* @return
*/
@Bean
PlatformTransactionManager platformTransactionManagerOne(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(localContainerEntityManagerFactoryBeanOne(builder).getObject());
}
}
/**
* basePackages 扫描所在接口的包
* entityManagerFactoryRef 引用配置的localContainerEntityManagerFactoryBeanOne
* transactionManagerRef 引用配置的 事务platformTransactionManagerOne
*/
@EnableJpaRepositories(basePackages = "org.lc.jpa.dao.dao2",entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanTwo",transactionManagerRef = "platformTransactionManagerTwo")
@Configuration
public class JpaConfigTwo {
@Autowired
@Qualifier("dataSourceTwo")
DataSource dataSourceTwo;
//注入yaml中的其他属性配置
@Autowired
JpaProperties jpaProperties;
@Primary
@Bean
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanTwo(EntityManagerFactoryBuilder builder) {
//注入数据源
return builder.dataSource(dataSourceTwo)
// 配置操作的实体bean
.packages("org.lc.jpa.bean")
// 注入配置属性文件
.properties(jpaProperties.getProperties())
// 初始化单元 不同即可
.persistenceUnit("pu1")
.build();
}
/**
* 事务的配置
* @param builder
* @return
*/
@Primary
@Bean
PlatformTransactionManager platformTransactionManagerTwo(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(localContainerEntityManagerFactoryBeanTwo(builder).getObject());
}
}
⑥两个不同包及名称的接口
public interface BookDaoOne extends JpaRepository<Book,Integer> {
}
public interface BookDaoTwo extends JpaRepository<Book,Integer> {
}
⑦测试
注入不同的dao进行测试
@Autowired
private BookDaoOne bookDaoOne;
@Autowired
private BookDaoTwo bookDaoTwo;
@Test
void multipleFind() {
List<Book> all = bookDaoOne.findAll();
System.out.println(all);
List<Book> all1 = bookDaoTwo.findAll();
System.out.println(all1);
}