springdata jpa

orm思想

  • 将实体类与数据表进行关联。
  • 将实体类的字段与数据表的字段进行关联。
  • 我们就可以像操作实体类一样操作数据库了,可以避免编写繁琐的sql语句。
  • hibernate框架是一套全自动的orm框架

springdata jpa,jpa,hibernate之间的关系

  • jpa规范本身提供了一套接口,是一套基于orm思想的规范。只要实现了jpa规范的框架,都可以使用jpa的接口进行操作。hibernate实现了jpa规范。
  • 比如,我们使用springdata jpa操作数据库时,内部干活的依然是hibernate框架,真正底层走的还是jdbc。
  • jpa的目标是提供更加简单的编程模型,方便开发人员的使用。
  • jpa还定义了独特的面向对象的查询语言,JPQL。
  • 而springdata jpa是对jpa规范的进一步封装。

springdata jpa的底层流程

  • 首先我们会定义一个接口继承两个接口JpaRepository ,JpaSpecificationExecutor
  • 当我们调用springdata jpa的接口进行数据表操作时,spring会通过动态代理技术生成一个动态代理对象,该对象也实现了那两个接口。
  • 然后此动态代理对象会调用hibernate框架进行操作,hibernate底层再通过jdbc操作数据库。

springdata jpa中实体类的配置

  • 实体类与数据库表映射配置。
@Entity //表明该类 (UserEntity) 为一个实体类,默认类名为表名
@Table(name = "user_message") //当表名与类名不同,使用@Table注解说明
@JsonIgnoreProperties(value = { "hibernateLazyInitializer"}) //防止因为有nul字段产生异常
public class UserMessage{
}
  • 类成员与数据库表主键映射的配置。
@Id  //表明该字段为主键
@GeneratorValue //配置主键的生成策略,它有两个属性,分别是strategy和generator
       //generator属性的值是一个字符串,默认为"",其声明了主键生成器的名称
       //strategy属性:提供四种值:-AUTO主键由程序控制, 是默认选项 ,不设置就是这个
                                //-IDENTITY 主键由数据库生成, 采用数据库自增长, Oracle不支持
                                //-SEQUENCE 通过数据库的序列产生主键, MYSQL不支持
                                //-Table 提供特定的数据库产生主键, 该方式更有利于数据库的移植
@Column(name = "userid") //表示成员与字段的映射
  • 类成员与普通字段的映射
@Column(name = "name") //对于普通字段只需要设置此注解即可

springdata jpa的基本使用

  • 在创建项目时选择web模块和jpa模块,jdbc模块,mysql模块
  • 在全局配置文件配置数据库
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.type=com.alibaba.druid.pool.
#create 启动时删数据库中的表,然后创建,退出时不删除数据表
#create-drop 启动时删数据库中的表,然后创建,退出时删除数据表 如果表不存在报错
#update 如果启动时表格式不一致则更新表,原有数据保留
#validate 项目启动表结构进行校验 如果不一致则报错
spring.jpa.hibernate.ddl-auto=update
  • 首先编写一个实体类 Use 使用注解配置表与字段的映射r。 需要注意实体类要有无参构造。
public class User {
    @Id
    @GeneratedValue
    private int id;
    @Column(name = "name")
    private String name;
    @Column(name = "city")
    private String city;
    //geter setter 构造
}
  • 然后编写一个dao层接口,继承JpaRepository<实体类,主键类型> 和JpaSpecificationExecutor<实体类>
//JpaRepository封装了基本的crud操作
//封装了复杂查询,比如分页
public interface UserResporisty extends JpaRepository<User,Integer> ,JpaSpecificationExecutor<User> {
}
  • JpaRepository接口常用的自带的操作数据表的方法
@Autowired
UserRepository userRepository;
@Test
public void test() {
    //添加或者更新一个记录   如果添加对象中没有主键表示保存,有主键表示更新
    User save = userRepository.save(new User());
    //根据主键查询一个记录
    User one = userRepository.getOne("id");
    //根据主键删除一个记录
    userRepository.deleteById("id");
    //查询所有记录 返回一个list集合
    List<User> all = userRepository.findAll();
    //查询表中记录的总数
    userRepository.count();
    //查询指定主键的记录是否存在
    boolean existsById = userRepository.existsById("id");
}
  • jpql进行查询(基于实体类和成员进行查询)
public interface UserResporisty extends JpaRepository<User,Integer> ,JpaSpecificationExecutor<User> {
    //使用@Query注解来支持jpql查询,jpql语句写到注解中,?1表示第一个参数 同样?2表示第二个参数
    @Query("SELECT u.login FROM User u WHERE u.id = ?1")
    String findUserNameByID(String user_id);
    
    //同样可以使用jpql完成更新操作
    @Transactional //对于更新操作必须添加事务支持否则会报错,
                   //在单元测试方法中注明事务,事务会自动回滚,可以设置@Rollback(value = false)不自动回滚
    @Modifying //代表此方法是一个更新操作
    @Query("update User m set m.readStatus = true where m.id = ?1")
    void updateReadStatusById(String id);
}
  • 也可以在query注解中声明nativeQuery = true,支持使用原生sql语句进行查询
public interface UserResporisty extends JpaRepository<User,Integer> ,JpaSpecificationExecutor<User> {
    //使用原生sql进行查询
    @Query(value = "select  * from t_user",nativeQuery = true)
    List<User> findAll();
    //原生sql也支持占位符
    @Query(value = "select  * from t_user where cust_name=? ",nativeQuery = true)
    User findByName(String name);
} 
  • 两表关联查询 查询的每条记录以Object 数组接收。
public interface SlaItchatDataRepository extends JpaRepository<User,String> {
    //全量查询情况1
    @Query(value = "select * from table1 left join table2 on table1.id = table2.id", nativeQuery = true)
    List<Object []> findjoindata();
}

编程式事务管理与声明式事务管理

  • 编程式事务管理使用TransactionTemplate 它可以手动控制事务的开启 提交和回滚。
  • 声明式事务管理基于springAOP实现,本质是将方法前后进行拦截,添加事务处理的功能。
  • 声明式事务管理使用非侵入式开发方式,将事务功能与业务代码分离,缺点是最细粒度只能作用到方法级,无法作用到代码块级别。

JPA事务管理

  • 在dao层代码@Modifying注解
    ①在@Query注解中,编写JPQL实现DELETE和UPDATE操作的时候,必须加上@modifying注解,以通知Spring Data 这是一个DELETE或UPDATE操作。
    ②UPDATE或者DELETE操作需要使用事务,此时需要定义Service层,在Service层的方法上添加事务操作。
    @Modifying
    @Query(value=“UPDATE hr_employee_contract t SET t.deleteStatus=1 WHERE t.id=?1”,nativeQuery = true)
    void delete(Long id);

  • 在service层代码使用@Transactional手动开启事务管理
    @Transactional注解其中使用较多的三个属性:readOnly、propagation、isolation。其中propagation属性用来枚举事务的传播行为,isolation用来设置事务隔离级别,readOnly进行读写事务控制。
    @Transactional
    @Override
    public void delete(Long id) {
    employeeContractDao.delete(id);
    }

  • readOnly属性
    从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据)
    可以避免不可重复读的问题。

事务实例

  • 编写实体类和dao层代码
public interface UserDao extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
}
  • 在service层实现转账功能
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    //转账 账户1向账户2转账 100元
    public void trans1(){
       User u1 =  userDao.getOne(4);
       User u2 =  userDao.getOne(5);
       u1.setMoney(u1.getMoney()-100);
       u2.setMoney(u2.getMoney()+100);
       userDao.save(u1);
       userDao.save(u2);
    }

    //转账 账户1向账户2转账 100元
    public void trans2(){
        User u1 =  userDao.getOne(4);
        User u2 =  userDao.getOne(5);
        u1.setMoney(u1.getMoney()-100);
        userDao.save(u1);
        int a = 1 / 0; //制造一个异常
        u2.setMoney(u2.getMoney()+100);
        userDao.save(u2);
    }

    //转账 账户1向账户2转账 100元
    @Transactional
    public void trans3(){
        User u1 =  userDao.getOne(4);
        User u2 =  userDao.getOne(5);
        u1.setMoney(u1.getMoney()-100);
        userDao.save(u1);
        int a = 1 / 0; //制造一个异常
        u2.setMoney(u2.getMoney()+100);
        userDao.save(u2);
    }
}
  • 对于函数1会正常转账
  • 对于函数2转账失败,但是没有手动添加事务,会发生账户1改变,账户2没有改变的情况
  • 对于函数3转账失败,但是手动添加了事务,发生异常时会回滚到转账前的状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值