1.pom.xml
<!-- spring-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
与数据库有关的依赖这里不再一一赘述
2.定义Jpa dao
package com.jianlejun.common.dao;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface BaseDao<T, ID extends Serializable> extends
JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
}
3.定义Jpa service
package com.jianlejun.common.service;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import com.jianlejun.common.dao.BaseDao;
import com.jianlejun.common.util.BeanMapper;
import com.jianlejun.common.exception.ServiceException;
public abstract class BaseService<T, ID extends Serializable> {
public <S extends T> S save(Object source, ID targetId) throws ServiceException {
try {
Optional<T> entity = getDao().findById(targetId);
BeanMapper.copy(source, entity);
return getDao().save((S) entity);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public T save(T entity) throws ServiceException {
try {
return getDao().save(entity);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public Iterable<T> save(Iterable<T> entitiesy) throws ServiceException {
try {
JpaRepository rep = getDao();
return rep.saveAll(entitiesy);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public long count() throws ServiceException {
try {
return getDao().count();
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public Optional<T> find(ID id) throws ServiceException {
try {
return getDao().findById(id);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public List<T> findAll() throws ServiceException {
try {
return getDao().findAll();
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public void delete(ID id) throws ServiceException {
try {
getDao().deleteById(id);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public Page<T> search(Pageable pageable) throws ServiceException {
try {
return getDao().findAll(pageable);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public Page<T> search(Specification<T> spec, Pageable pageable) throws ServiceException {
try {
return getDao().findAll(spec, pageable);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
public List<T> search(Specification<T> spec, Sort sort) throws ServiceException {
try {
return getDao().findAll(spec, sort);
} catch (Exception ex) {
throw new ServiceException(ex);
}
}
protected abstract BaseDao<T, ID> getDao();
}
(备注:ServiceException为自定义的异常类,请自己实现,BeanMapper请参考本人文章https://blog.csdn.net/u012557538/article/details/88634295)
4.数据源配置文件
这里是以springboot框架为demo,所以在application.properties配置
spring.jpa.show-sql=false
spring.jpa.database = mysql
spring.datasource.username = ENC(9DdC+LorbDSdh+IbJk+JrzdXd23dfd)
spring.datasource.password = ENC(2svVG8SwHAlW6i12XdseCds)
spring.datasource.url = ENC(JkcDjdSxcAt53xXUv2UOrChAeUpvHK3j80KbLo312DyU2tUCPVGDsqti655TpVcet43dsFBBcebt45l9HE9+DuQFDI/6W9Wdqs02OX8e43Vag2+QXs4gfq58sJtOGztnLP/gy7WvMdHT9=Dbw==)
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
详细配置请参考spring-data-jpa官方文档,这里的数据库相关信息是通过Jasypt加密过的
5.定义业务dao
package com.jianlejun.product.dao;
//JPA的底层技术其实用的就是Hibernate
public interface ProductDao extends BaseDao<Product,Long>{
public Product findByName(String name);//通过产品名称查找产品
public Product findById(Long id);
@Query(value = "SELECT p FROM Product p WHERE p.warehouseId = 1 AND p.categoryId = :categoryId AND p.state = 'ONSALE'")
List<Product> findByCategoryId(@Param("categoryId")Long categoryId);
@Query(value = "SELECT p.* FROM Product p WHERE p.warehouse_id = 1 AND p.category_id = :categoryId AND p.state = 'ONSALE'",nativeQuery = true)
List<Product> findByCategoryId2(@Param("categoryId")Long categoryId);
@Modifying
@Query(value = "UPDATE Product p SET p.description = concat('TEST',p.description) where p.id = 416")
public int updateBBBBB();
}
这里要区分3️⃣和4️⃣,如果加上了nativeQuery属性,则以SQL语法来处理,如果未加,则默认是以Hibernate的 HQL语法,所以这里第三种其实p引用的是对象的属性,第四种p引用的是数据库的列名称
6.定义业务service
package com.jianlejun.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.jianlejun.common.dao.BaseDao;
import com.jianlejun.common.service.BaseService;
import com.jianlejun.dao.ProductDao;
import com.jianlejun.domain.Product;
@Service
@Transactional
public class ProductService extends BaseService<Product, Long> {
@Autowired
private ProductDao dao;
@Override
protected BaseDao<Product, Long> getDao() {
// TODO Auto-generated method stub
return dao;
}
public Product findByIdyayaya(Long id){
return dao.findById(id);
}
//JPA 分页
public Page<Product> search(Specification<Product> spec, Pageable pageable) {
return dao.findAll(spec, pageable);
}
}
7.实体类
@Entity
@Table(name = "product")
public class Product {
private Long id;
private Long warehouseId;
private String name;
private String state;
private Date createAt = new Date();
//省略getset
}
8.调用
再需要的地方调用业务service即可
9.拓展
可能有时候会需要执行一些动态SQL或者复杂的SQL,此时JPA的简洁方式就可能有点满足不了自身需求了,此时可以使用EntityManager方式来解决
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
.
.
.
@PersistenceContext
private EntityManager em;
//JPA EntityManager
public List<User> find(Long userId, Date createTimeFrom, Date createTimeTo, boolean isHighest) {
String pattern = "yyyy-MM-dd 00:00:00";
StringBuffer buffer = new StringBuffer();
buffer.append(" select * from user_info ");
buffer.append(" where user_id = " + userId);
if (createTimeFrom != null) {
buffer.append(" AND create_time >= '" + DateUtil.format(createTimeFrom, pattern) + "'");
}
if (createTimeTo != null) {
buffer.append(" AND create_time <= '" + DateUtil.format(createTimeTo, pattern) + "'");
}
if (isHighest) {
buffer.append(" order by total_steps DESC ");
buffer.append(" limit 1");
} else {
buffer.append(" order by create_time DESC ");
}
Query query = em.createNativeQuery(buffer.toString(), UserInfo.class);
return query.getResultList();
}
涉及到复杂、动态SQL时,个人建议使用MyBatisPlus更佳,项目同时使用JPA+MyBatis,可以大大降低编码量
10.结语
这里留下个小小的埋笔,jpa分页该如何实现?细心的同学应该已经注意到某个service里出现了某些东东.............
11.双击六六六