JPA的继承注解一般有四种
@MappedSuperclass
这个注解应用的场景是父类不对应任何单独的表,多个子类共用相同的属性。
注意:
@MappedSuperclass
注解使用在父类上面,是用来标识父类的作用
@MappedSuperclass
标识的类表示其不能映射到数据库表,因为其不是一个完整的实体类,但是它所拥有的属性能够映射在 其子类对用的数据库表中
@MappedSuperclass
标识得类不能再有@Entity或@Table
注解 但是可以使用@Id 和@Column
注解
@Inheritence
此注解应用于根实体类以定义继承策略。 如果没有使用此注释定义策略类型,那么它遵循单表战略。
单表策略:
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
查询父类关联的表 在查询父类的时候 所有子类表中字段全部查询出来
连接策略:
@Inheritance(strategy=InheritanceType.JOINED)
在连接策略中,为每个实体类生成一个单独的表。 每个表的属性都与主键连接。 它消除了字段字重复的可能性。但是父类中除了主键的的其他字段 并不会在子表中查询出来
按类表策略:
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
在按类表策略中,为每个子实体类生成一个单独的表。 与连接策略不同,在按类表策略中不会为父实体类生成单独的表
@DiscriminatorColumn
鉴别器属性将一个实体与另一个实体区分开来。 因此,该注释用于提供鉴别器列的名称。 仅需要在根实体类上指定此注释。
@DiscriminatorValue
此注释用于指定表示特定实体的值的类型。 需要在子实体类中指定此注释。
@MappedSuperclass 测试
准备两张表:t_user,t_address。
t_user
CREATE TABLE `t_user` (`rid` bigint NOT NULL,`user_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,`email` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,`phone` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,PRIMARY KEY (`rid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
t_address
CREATE TABLE `t_address` (`rid` bigint NOT NULL,`province` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,`city` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,`county` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,PRIMARY KEY (`rid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
BaseEntity 实体类,使用@MappedSuperclass注解,标识属性能够映射在其子类对用的数据库表中
@MappedSuperclass
public class BaseEntity {@Id@Column(name = "rid",nullable = false)private Long rid;public Long getRid() {return rid;}public void setRid(Long rid) {this.rid = rid;}
}
t_user实体类:
@Entity
@Table(name = "t_address")
public class Address extends BaseEntity{@Column(name = "province")private String province;@Column(name = "city")private String city;@Column(name = "county")private String county;public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getCounty() {return county;}public void setCounty(String county) {this.county = county;}
}
t_address:
@Entity
@Table(name = "t_address")
public class Address extends BaseEntity{@Column(name = "province")private String province;@Column(name = "city")private String city;@Column(name = "county")private String county;public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getCounty() {return county;}public void setCounty(String county) {this.county = county;}
}
userRepository接口继承JpaRepository,JpaSpecificationExecutor实现crud操作。
public interface UserRepository extends JpaRepository<User,Long>,JpaSpecificationExecutor<User> {
}
addressRepository接口继承JpaRepository,JpaSpecificationExecutor实现crud操作。
public interface AddressRepository extends JpaRepository<Address,Long>, JpaSpecificationExecutor<Address> {
}
配置数据库连接在application.yml
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456url: jdbc:mysql://127.0.0.1:3306/testdemo?serverTimezone=UTC
测试:
@Autowiredprivate AddressRepository addressRepository;@Testvoid contextLoads() {Address address = new Address();address.setRid(1L);address.setProvince("四川省");address.setCity("成都市");address.setCounty("金牛区");addressRepository.save(address);}
@Autowiredprivate UserRepository userRepository;@Testvoid userTest(){User user = new User();user.setRid(1L);user.setUserName("祝八一");user.setEmail("123@qq.com");user.setPhone("1878265xxxx");userRepository.save(user);}
可见在baseEntity
里面的rid也插入进了数据库
jpa配置多数据源
1.首先把application.yml
里面的数据源的配置先注释了。
换成如下的配置
spring:datasource:db1:url: jdbc:mysql://127.0.0.1:3306/testdemo?serverTimezone=UTC#数据库用户名username: root#数据库密码password: 123456#mysql数据库驱动程序(重要)driverClassName: com.mysql.cj.jdbc.Driverdb2:url: jdbc:mysql://127.0.0.1:3306/shop?serverTimezone=UTC#数据库用户名username: root#数据库密码password: 123456#mysql数据库驱动程序(重要)driverClassName: com.mysql.cj.jdbc.Driver
2.编写数据源配置类
@ConfigurationProperties(prefix = "spring.datasource.db1")
@Component
@Data
public class Db1Properties {private String url;private String username;private String password;private String driverClassName;
}
@ConfigurationProperties(prefix = "spring.datasource.db2")
@Component
@Data
public class Db2Properties {private String url;private String username;private String password;private String driverClassName;
}
Db1Config、Db2Config
以下两个是需要修改的配置信息
设置@EnableJpaRepositories注解里的basePackages
属性配置jpa持久化类的包路径
设置db1EntityManagerFactory方法中的packages方法设置实体类所在的包路径
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "db1EntityManagerFactory",transactionManagerRef = "db1TransactionManager",//basePackages = {"com.zhubayi.jpademo.repository.user"})// 指定该数据源操作的DAO接口包basePackageClasses = UserRepository.class) //定一个要扫描包中的一个类或接口,将扫描所在包中的所有repository。
public class Db1Config {@Autowired@Qualifier("db1DataSource")private DataSource db1DataSource;@PersistenceUnit(name = "db1PersistenceUnit")@Primary@Bean(name = "db1EntityManagerFactory")public LocalContainerEntityManagerFactoryBean db1EntityManagerFactory() {LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();em.setDataSource(db1DataSource);em.setPersistenceUnitName("db1PersistenceUnit");em.setPackagesToScan(new String[]{"com.zhubayi.jpademo.entity"});HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();//开启sql展示vendorAdapter.setShowSql(true);em.setJpaVendorAdapter(vendorAdapter);return em;}@Primary@Bean(name = "db1TransactionManager")public PlatformTransactionManager db1TransactionManager(@Qualifier("db1EntityManagerFactory") EntityManagerFactory factory) {return new JpaTransactionManager(factory);}}@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "db2EntityManagerFactory",transactionManagerRef = "db2TransactionManager",//basePackages = {"com.zhubayi.jpademo.repository.address})// 指定该数据源操作的DAO接口包basePackageClasses = AddressRepository.class)//定一个要扫描包中的一个类或接口,将扫描所在包中的所有repository。
public class Db2Config {@Autowired@Qualifier("db2DataSource")private DataSource db2DataSource;@PersistenceUnit(name ="db2PersistenceUnit")@Bean(name = "db2EntityManagerFactory")public LocalContainerEntityManagerFactoryBean db2EntityManagerFactory() {LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();em.setDataSource(db2DataSource);em.setPersistenceUnitName("db2PersistenceUnit");em.setPackagesToScan(new String[]{"com.zhubayi.jpademo.entity"});HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();//开启sql展示vendorAdapter.setShowSql(true);em.setJpaVendorAdapter(vendorAdapter);return em;}@Bean(name = "db2TransactionManager")public PlatformTransactionManager db2TransactionManager(@Qualifier("db2EntityManagerFactory") EntityManagerFactory factory) {return new JpaTransactionManager(factory);}
}
@EnableJpaRepositories注解说明
value
:basePackages的别名,简化basePackages。
basePackages
:用于配置扫描Repositories
所在的包。填写字符串(或字符串数组)形式的包名。
basePackageClasses
:basePackages的安全替代选选项。指定一个要扫描包中的一个类或接口,将扫描所在包中的所有repository
。
可以考虑在每个要扫描的包中创建一个类或接口,它除了被这个属性引用外,没有其他用途。
includeFilters
:指定哪些类型的组件被扫描。
**excludeFilters**
:指定哪些类型的组件不被扫描。
repositoryImplementationPostfix
:查找自定义存储库实现时要使用的后缀。默认为Impl。对于名为PersonRepository的存储库,将通过扫描PersonRepositoryImpl来查找相应的实现类。
namedQueriesLocation
:配置Spring-Data的named queries 属性文件的位置,默认META-INF/jpa-named-queries.properties。
queryLookupStrategy
:查询方法的查询策略。默认为QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND。
repositoryFactoryBeanClass
:用于每个存储库实例的FactoryBean类。默认为JpaRepositoryFactoryBean。
repositoryBaseClass
:配置存储库基类,以用于为该特定配置创建存储库代理。
entityManagerFactoryRef:配置EntityManagerFactory bean定义的名称。默认为entityManagerFactory。
transactionManagerRef
:配置PlatformTransactionManager bean定义的名称。默认为transactionManager。
considerNestedRepositories
:配置是否发现嵌套的Repository接口(如定义为内部类)。默认为false。
enableDefaultTransactions
:配置Spring-Data-Jpa 的Repositories是否启用默认事务,默认为true。如果禁用,则必须在外层使用。
bootstrapMode
:配置在引导生命周期中何时初始化Repository。默认为BootstrapMode.DEFAULT,除了添加了BootstrapMode.LAZY的接口外,其他接口立即初始化。
BootstrapMode.LAZY,Repository的bean定义被认为是懒加载注入,并且只在首次使用时初始化,即应用程序可能在没有初始化Repository的情况下完全启动。
BootstrapMode.DEFERRED,Repository的bean定义被认为是懒加载注入,但存储库初始化在应用程序上下文引导完成时触发。
escapeCharacter
:配置在包含contains、startsWith或endsWith子句的派生查询中用于转义 _ 或 % 的通配符字符。
3.目录结构
测试:
user测试:
根据配置文件application.yml
得知user
在testdemo
数据库中。
此时数据库没有数据。
然后执行之前的userTest
测试。
插入成功!
address测试:
根据配置文件application.yml
得知address
在shop
数据库中。
此时数据库没有数据。
然后执行之前的contextLoads
测试。
去shop
数据库查看
插入成功!
jpa分页条件查询
首先在t_address数据库添加五条数据。
然后在Address实体类里重写oString方法。
@Overridepublic String toString() {return "Address{" +"province='" + province + '\'' +", city='" + city + '\'' +", county='" + county + '\'' +'}';}
然后进行测试
@Testvoid pageTest(){int pageNum=1;int pageSize=2;Specification<Address> specification =(root, criteriaQuery, criteriaBuilder) -> {//Pridicate:表示一个查询条件List<Predicate> predicates = new ArrayList<>();//创建一个条件集合//获取属性Path<String> rid = root.get("province");//构造查询条件predicates.add(criteriaBuilder.equal(rid, "四川省"));//必须使用toArray(T[])的有参数方法,因为cq.where(p)中的参数的类型必须是Predicate[]数组类型。//toArray()无参返回的是一个Object类型。//新建数组方式之一:new A[number]return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));};Pageable pageable = PageRequest.of(pageNum - 1, pageSize, Sort.Direction.ASC, "rid");Page<Address> addressPage = addressRepository.findAll(specification, pageable);addressPage.forEach(System.out::println);System.out.println("总页数:"+addressPage.getTotalPages());}
输出: