Spring Data Jpa

 阅读约 9 分钟

1. JPA是什么?

Java Persistence API:用于对象持久化的一组API。

JPA的思想就是:可以用Java代码实现的,为什么还要自己去编写sql语句?其核心的一切都是围绕如何拼接SQL语句进行的。

2、Spring Data

Spring Data 是 Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系型数据存储。其主要目标是使数据库的访问变得方便快捷。Spring Data 具有如下特点:

1、SpringData 项目支持 NoSQL 存储:

MongoDB (文档数据库)
Neo4j(图形数据库)
Redis(键/值存储)
Hbase(列族数据库)

2、SpringData 项目所支持的关系型数据存储技术:

JDBC
JPA

3、使用jpa需要给实体类加注解

@Entity(name = "t_book")
public class Book {
    private Long id;
    private String name;
    private String author;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }
    // 省略其他getter/setter
}

@Entity注解表示这是一个实体类,那么在项目启动时会自动针对该类生成一张表,默认的表名为类名,如果使用了name属性表示自定义生成的表名。@Id注解表示这个字段是一个id,@GeneratedValue注解表示主键采用自增长策略,对于类中的其他属性,默认都会根据属性名在表中生成相应的字段,字段名和属性名相同,如果开发者想要对字段进行定制,可以使用@Column注解,去配置字段的名称,长度,是否为空等等。

4、多条件单表查询

构建谓语

Specification<Product> specification = new Specification<Product>() {
            @Override
            public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Expression<String> idCol = root.get("id");
                Expression<BigDecimal> rewardRateCol = root.get("rewardRate");
                Expression<String> statusCol = root.get("status");
                List<Predicate> predicates = new ArrayList<>();
                if (idList != null && idList.size() > 0) {
                    predicates.add(idCol.in(idList));   //##1
                }
                if (minRewardRate != null && BigDecimal.ZERO.compareTo(minRewardRate) < 0) {
                    predicates.add(cb.ge(rewardRateCol, minRewardRate));     //##2
                }
                if (maxRewardRate != null && BigDecimal.ZERO.compareTo(maxRewardRate) < 0) {
                    predicates.add(cb.le(rewardRateCol, maxRewardRate));
                }
                if (statusList != null && statusList.size() > 0) {
                    predicates.add(statusCol.in(statusList));
                }

                query.where(predicates.toArray(new Predicate[0]));
                return null;
            }
        };
        Page<Product> page = repository.findAll(specification, pageable);

谓语是什么呢?按我的理解,谓语就是一个条件限定词。
1、使用Expression的in方法构建了一个包含的条件(或谓语),查询结果的id需要包含在idList里。
2、我们使用criteriaBuilder的ge方法构建了一个大于的条件(或谓语),该条件要求收益率大于指定的值。

5、自定义查询@Query的使用

@Query(value = "SELECT CONCAT_WS('|', order_id,outer_order_id,chan_id,chan_user_id,product_id,order_type,amount,DATE_FORMAT( create_at,'%Y-%m-%d %H:%i:%s')) FROM order_t WHERE order_status = 'success' AND chan_id = ?1 AND create_at >= ?2 AND create_at < ?3",nativeQuery = true)
    List<String> queryVerifiableOrders(String chanId, Date start, Date end);

这里有三个参数,对应三个占位符,占位符是固定写法。还有另外一种使用命名参数的方式。
nativeQuery = true表示这里使用的是原生态的sql查询语句。

6、合法参数校验

Spring 采用一个 org.springframework.util.Assert 通用类完成这一任务。
Assert 翻译为中文为“断言”,使用过 JUnit 的读者都熟知这个概念,它断定某一个实际的运行值和预期想一样,否则就抛出异常。Spring 对方法入参的检测借用了这个概念,其提供的 Assert 类拥有众多按规则对方法入参进行断言的方法,可以满足大部分方法入参检测的要求。这些断言方法在入参不满足要求时就会抛出 。IllegalArgumentException。
常用断言方法源码分析:

public static void notNull(@Nullable Object object, String message) {
        if (object == null) {
            throw new IllegalArgumentException(message);
        }
    }

当object为null时抛出异常。


public static void isTrue(boolean expression, String message) {
        if (!expression) {
            throw new IllegalArgumentException(message);
        }
    }

当 expression 为true通过,flase时抛出异常。

7、Log4j

Log4j建议只使用四个级别,优先级从高到低分别是 ERROR、WARN、INFO、DEBUG。

通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别, 则应用程序中所有DEBUG级别的日志信息将不被打印出来。优先级高的将被打印出来。项目上生产环境时候一定得把debug的日志级别重新调为warn或者更高,避免产生大量日志。

8、配置多数据源

目标

@Test
public void queryOrder(){
    System.out.println(orderRepository.findAll());
    System.out.println(readOrderRepository.findAll());
}

orderRepository.findAll()连接的是主库、生成订单。

readOrderRepository.findAll()连接的是从库、生成对账文件、保存渠道的订单信息。

目标定好了,如何实现呢?
有什么方法帮助自己找到答案?

9、学习经验

1、如果如果遇到不太熟悉的代码,主要通过点击方法查看源码寻找答案,JDK相关的才看官方API文档。框架相关的资料大多不完善,找文档很费时间,点击方法看看源码是怎么实现的,足以解决问题。

阅读 215更新于 4月16日

推荐阅读
目录