一、SpringData JPA是什么?
Spring Data JPA(Java Persistence API),是Spring框架的主要构建块之一。如果您想使用持久数据,它也是一个强大的工具。
Spring Data JPA的核心目标之一是减少代码并简化数据访问层,同时仍保留丰富且功能齐全的功能集。
二、核心关键字
JPQL(JavaPersistence Query Language)是一种面向对象的查询语言,它在框架中最终会翻译成为sql进行查询,如果不知JPQL请大家自行谷歌了解一下,如果你会SQL,了解这个应该不废吹灰之力。
使用SpringDataJPA进行JPQL/SQL一般查询的核心是@Query注解,我们先来看看该注解
@Retention(RetentionPolicy.RUNTIME)//运行时
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})//注解使用的注解位置为方法、注解类型
@QueryAnnotation
@Documented
public @interface Query {
String value() default "";
String countQuery() default "";
String countProjection() default "";
boolean nativeQuery() default false;
String name() default "";
String countName() default "";
}
@Retention元注解,RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在,即是运行时的状态。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})//注解使用的注解位置为方法、注解类型
@QueryAnnotation标识这是一个查询注解;
@Documented 注解表明这个注解应该被 javadoc工具记录
@Query注解中有6个参数,value参数是我们需要填入的JPQL/SQL查询语句;nativeQuery参数是标识该查询是否为原生SQL查询,默认为false;countQuery参数为当你需要使用到分页查询时,可以自己定义(count查询)计数查询的语句,如果该项为空但是如果要用到分页,那么就使用默认的主sql条件来进行计数查询;name参数为命名查询需要使用到的参数,一般配配合@NamedQuery一起使用;countName参数作用与countQuery相似,但是使用的是命名查询的(count查询)计数查询语句;countProjection为涉及到投影部分字段查询时的计数查询(count查询)。
三、项目准备
3.1、采用springboot项目,
1.8
org.springframework.boot
spring-boot-starter-parent
2.1.7.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
5.1.32
com.alibaba
fastjson
1.2.55
com.alibaba
druid
1.0.29
@SpringBootApplication
public class VdeMasterApplication {
public static void main(String[] args) {
SpringApplication.run(VdeMasterApplication.class, args);
}
}
3.2、application.properties配置
#######################################数据库配置##################################
spring.datasource.url=jdbc:mysql://192.168.3.7:3306/vde_dev?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false
#添加数据库连接池才需要
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=sa2019
#######################################SpringData配置##################################
#配置自动建表:updata:没有表新建,有表更新操作,控制台显示建表语句
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
3.3、数据库Sql准备:
CREATE TABLE `vde` (
`id` int(11) NOT NULL COMMENT '自增ID',
`board` varchar(255) DEFAULT NULL COMMENT '主板名称',
`brand` varchar(255) DEFAULT NULL COMMENT '品牌名称',
`device` varchar(255) DEFAULT NULL COMMENT '设备名',
`display` varchar(255) DEFAULT NULL COMMENT '软件构建版本号',
`manufacturer` varchar(255) DEFAULT NULL COMMENT '硬件制造商',
`model` varchar(255) DEFAULT NULL COMMENT '型号',
`os` varchar(255) DEFAULT NULL COMMENT '系统版本',
`product` varchar(255) DEFAULT NULL COMMENT '手机厂商',
`version` varchar(255) DEFAULT NULL COMMENT '固件版本号',
`iccid` varchar(255) DEFAULT NULL COMMENT 'iccid',
`imei` varchar(255) DEFAULT NULL COMMENT 'imei',
`imsi` varchar(255) DEFAULT NULL COMMENT 'imsi',
`ip` varchar(255) DEFAULT NULL COMMENT 'ip',
`operator` varchar(255) DEFAULT NULL COMMENT '运营商',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='VDE信息表';
INSERT INTO `vde_dev`.`vde` (`id`, `board`, `brand`, `device`, `display`, `manufacturer`, `model`, `os`, `product`, `version`, `iccid`, `imei`, `imsi`, `ip`, `operator`) VALUES ('8', 'sdm710', '360', 'QK1809', 'V112', '360', '1809-A01', '8.1.0', 'QK1809', 'OPM1', '89860117801606100123', '869585031739071', '460015547625788', '10.98.223.11', '46001');
INSERT INTO `vde_dev`.`vde` (`id`, `board`, `brand`, `device`, `display`, `manufacturer`, `model`, `os`, `product`, `version`, `iccid`, `imei`, `imsi`, `ip`, `operator`) VALUES ('10', 'bullhead', 'google', 'bullhead', 'OPM7.181205.001', 'LGE', 'Nexus 5X', '8.1.0', 'bullhead', 'OPM7.181205.001', '89860117801058542442', '353627075256308', '460015547621765', '10.77.169.57', '46001');
INSERT INTO `vde_dev`.`vde` (`id`, `board`, `brand`, `device`, `display`, `manufacturer`, `model`, `os`, `product`, `version`, `iccid`, `imei`, `imsi`, `ip`, `operator`) VALUES ('11', 'QC_Reference_Phone', 'OnePlus', 'OnePlus3T', 'ONEPLUS A3010_28_171115', 'OnePlus', 'ONEPLUS A3010', '7.1.1', 'OnePlus3', 'NMF26F', '89860011191446092063', '864854036497043', '460028137299278', '10.28.79.195', '46000');
INSERT INTO `vde_dev`.`vde` (`id`, `board`, `brand`, `device`, `display`, `manufacturer`, `model`, `os`, `product`, `version`, `iccid`, `imei`, `imsi`, `ip`, `operator`) VALUES ('12', 'sdm636', 'xiaomi', 'whyred', 'PKQ1.180904.001', 'Xiaomi', 'Redmi Note 5', '9', 'whyred', 'PKQ1.180904.001', '89860317947552820897', '867192036035050', '460110415456028', '10.94.21.104', '46011');
3.4、解析
JpaRepository中,定义了一些常用的接口,里面的都可以直接使用。
@NoRepositoryBean
public interface JpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor {
List findAll();
List findAll(Sort var1);
List findAllById(Iterable var1);
List saveAll(Iterable var1);
void flush();
S saveAndFlush(S var1);
void deleteInBatch(Iterable var1);
void deleteAllInBatch();
T getOne(ID var1);
List findAll(Example var1);
List findAll(Example var1, Sort var2);
}
3.5、项目代码
@Entity
@Table(name = "vde")
public class Vde implements Serializable {
@Id
@GeneratedValue
private Integer id;
/**
* 品牌名称
*/
private String brand;
/**
* 型号
*/
private String model;
/**
* 主板名称
*/
private String board;
/**
* 系统版本
*/
private String os;
/**
* 硬件制造商
*/
private String manufacturer;
/**
* 版本
*/
private String version;
/**
* 手机厂商
*/
private String product;
/**
* 软件构建版本号
*/
private String display;
/**
* 设备号
*/
private String device;
/**
* imsi
*/
private String imsi;
/**
* iccid
*/
private String iccid;
/**
* imei
*/
private String imei;
/**
* ip
*/
private String ip;
/**
* 网络运营商
*/
private String operator;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getBoard() {
return board;
}
public void setBoard(String board) {
this.board = board;
}
public String getOs() {
return os;
}
public void setOs(String os) {
this.os = os;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getProduct() {
return product;
}
public void setProduct(String product) {
this.product = product;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
public String getDevice() {
return device;
}
public void setDevice(String device) {
this.device = device;
}
public String getImsi() {
return imsi;
}
public void setImsi(String imsi) {
this.imsi = imsi;
}
public String getIccid() {
return iccid;
}
public void setIccid(String iccid) {
this.iccid = iccid;
}
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getOperator() {
return operator;
}
public void setOperator(String operator) {
this.operator = operator;
}
}
@Query是用来配置自定义SQL的注解,后面参数nativeQuery = true才是表明了使用原生的sql,如果不配置,默认是false,则使用HQL查询方式。
HRL查询,查询全部信息,注意HRL查询的是实体类的名称,不是数据表的名称,特别注意这一点
@Repository
public interface VdeRepository extends JpaRepository {
//@Query是用来配置自定义SQL的注解,后面参数nativeQuery = true才是表明了使用原生的sql,如果不配置,默认是false,则使用HQL查询方式。
//HRL查询,查询全部信息,注意HRL查询的是实体类的名称,不是数据表的名称,特别注意这一点
@Modifying
@Query(value = "update vde v set v.imei=?1 where v.id=?2",nativeQuery = true)
int updateImeiById(String imei,Integer id);
//原生sql查询
@Query(value = "select id from vde where id = (SELECT MAX(id) from vde)", nativeQuery = true)
public Integer queryMaxId();
//hql查询
@Query(value = "from Vde v where v.imei=?1 and v.model=?2")
public Vde findByImeiAndModelFromHql(String imei, String model);
//?查询
@Query(value = "select * from vde v where v.imei=?1 and v.model=?2", nativeQuery = true)
public Vde findByImeiAndModelFromSql(String imei, String model);
//param查询
@Query(value = "from Vde v where v.imei=:imei and v.imsi=:imsi")
public Vde findByImeiAndImsiFromParam(@Param("imei") String imei, @Param("imsi") String imsi);
//展示like模糊查询
@Query(value = "from Vde v where v.imei like %:imeiLike%")
List findByImeiLike(@Param("imeiLike")String imeiLike);
//展示使用Spring自带分页查询
@Query(value = "select * from vde v" ,nativeQuery = true)
Page findAllPage(Pageable pageable);
//展示带有条件的分页查询
@Query(value = "from Vde v where v.imei like %:imeiLike%")
Page findPageLikeImeiByHql(Pageable pageable, @Param("imeiLike")String imeiLike);
//展示带有条件的分页查询
@Query(value = "select * from vde v where v.imei like %:imeiLike%",nativeQuery = true)
Page findPageLikeImeiBySql(Pageable pageable, @Param("imeiLike")String imeiLike);
}
3.4、测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class VdeMasterApplicationTests {
final Logger LOGGER = LoggerFactory.getLogger(VdeMasterApplicationTests.class);
@Autowired
private VdeRepository vdeRepository;
@Test
public void save() {
Vde vde = new Vde();
vde.setBoard("测试数据");
vdeRepository.save(vde);
}
@Test
public void delete() {
vdeRepository.deleteById(14);
}
@Test
@Transactional
public void update() {
//Executing an update/delete query 报错,需要加上事务处理
vdeRepository.updateImeiById("imei_update",16);
}
@Test
public void findAll() {
LOGGER.info("findAll:" + vdeRepository.findAll().size());
}
@Test
public void getMaxId() {
LOGGER.info("maxId_native_sql:" + vdeRepository.queryMaxId());
}
@Test
public void findByImeiAndModel() {
LOGGER.info("vde_hql:" +vdeRepository.findByImeiAndModelFromHql("869585031739071","1809-A01"));
}
@Test
public void findByImeiAndModelBySQL() {
LOGGER.info("vde_native_sql:" +vdeRepository.findByImeiAndModelFromSql("869585031739071","1809-A01"));
}
@Test
public void findByImeiAndModelByHQLAndParam() {
LOGGER.info("vde_hql_param:" +vdeRepository.findByImeiAndImsiFromParam("869585031739071","460015547625788"));
}
@Test
public void findByImeiLike() {
LOGGER.info("vde_hql_like:" +vdeRepository.findByImeiLike("869585031739071"));
}
@Test
public void findAllPage() throws Exception{
//new PageRequest已经不推荐使用
Pageable pageable = PageRequest.of(1,2);
Page page = vdeRepository.findAllPage(pageable);
List list = page.getContent();
LOGGER.info("findAllPage_sql:"+list);
}
@Test
public void findPageLikeImei() throws Exception{
//new PageRequest已经不推荐使用
Pageable pageable = PageRequest.of(0,5,new Sort(Sort.Direction.ASC,"id"));
Page page = vdeRepository.findPageLikeImeiByHql(pageable,"869585031739071");
List list = page.getContent();
LOGGER.info("findPageLikeImei_hql:"+list);
}
@Test
public void findPageLikeImeiBySql() throws Exception{
//new PageRequest已经不推荐使用
Pageable pageable = PageRequest.of(0,5,new Sort(Sort.Direction.ASC,"id"));
Page page = vdeRepository.findPageLikeImeiBySql(pageable,"869585031739071");
List list = page.getContent();
LOGGER.info("findPageLikeImeiBy_sql:"+list);
}
}
3.5事务
事务一般是在service层,进行处理,例如:
public interface VdeService {
/**
* @param vde
* @return
* @throws Exception
* @todo 添加VDE
*/
public Vde add(Vde vde) throws Exception;
/**
* @return
* @throws Exception
* @todo 查询列表
*/
public List list() throws Exception;
/**
* @return
* @throws Exception
* @todo 随机查询VDE
*/
public Vde get() throws Exception;
}
@Service
public class VdeServiceImpl implements VdeService {
@Autowired
private VdeRepository vdeRepository;
@Override
@Transactional(rollbackFor = Exception.class)
public Vde add(Vde vde) throws Exception {
return vdeRepository.save(vde);
}
@Override
public List list() throws Exception {
return vdeRepository.findAll();
}
@Override
public Vde get() throws Exception {
List list = vdeRepository.findAll();
return list.get(list.size() - 1);
}
}
每个方法已经进行测试,测试结果只展示个别:
添加数据:
分页查询: