Spring Data Jpa 实现简单的CRUD操作

Spring Data Jpa 实现简单的CRUD操作

Scroll Down

环境搭建

创建maven项目导入坐标

<!-- junit单元测试 -->
<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
</dependency>

<!--spring data jpa-->
<dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>2.4.2</version>
</dependency>

<!--jpa的实现hibernate核心包-->
<dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.27.Final</version>
</dependency>


<!-- c3p0数据库连接池 -->
<dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
</dependency>

<!-- log日志 -->
<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.6</version>
</dependency>

<!--spring 测试-->
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.2</version>
            <scope>test</scope>
</dependency>

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
</dependency>

编写Spring配置类(纯java方式整合)

@Configuration
@EnableJpaRepositories(basePackages="cn.itcast.dao") // jpa要扫描的dao接口包
@EnableTransactionManagement //开启事务管理
@ComponentScan("cn.itcast") //spring 扫描的包
public class SpringConfig {

    /*
    * 配置数据源
    * */
    @Bean
    public DataSource dataSource() {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        try {
            comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jpa?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC");
        comboPooledDataSource.setUser("root");
        comboPooledDataSource.setPassword("123456");
        return comboPooledDataSource;
    }

    /*
    * 整合spring data jpa
    * */
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();

        //jpa的供应商适配器
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        // 自动创建数据库表
        vendorAdapter.setGenerateDdl(true);
        // 显示sql语句
        vendorAdapter.setShowSql(true);
        // 指定数据库类型
        vendorAdapter.setDatabase(Database.MYSQL);
        // 指定数据库方言,mysql默认方言MySQL57InnoDBDialect,即MySQL5.7版本以上才行
//        vendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL57InnoDBDialect");
        factory.setJpaVendorAdapter(vendorAdapter);

        factory.setJpaDialect(new HibernateJpaDialect());
        // jpa要扫描的实体类
        factory.setPackagesToScan("cn.itcast.domain");
        factory.setDataSource(dataSource);
    }

    /*
    * 事务管理器
    * */
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {

        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }
}

编写实体类

@Data
@Entity
@Table(name="sys_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id; // 尽量使用包装类
    @Column(name = "sys_username",length = 50)
    private String username;
    @Column(name = "sys_password",length = 50)
    private String password;
    @Column(name = "sys_money")
    private Integer money;
}

数值类型尽量使用包装类,如Integer的默认为null,而int默认是0,在后续的更新操作中会有影响

编写Dao层接口

public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {

}

你没有看错,就是继承JpaRepositoryJpaSpecificationExecutor这两个接口好了。其中:

  • JpaRepository<<User, Integer> : 用于简单的CRUD操作,User表示要操作的实体类,Integer表示该实体类主键的类型
  • JpaSpecificationExecutor<User> : 用于复杂查询(动态条件查询、分页等等)

编写测试类

本案例将使用spring整合junit作为测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserTest {
    @Autowired
    private UserDao userDao;

    //   即将要写的测试用例
}

到此环境搭建已经完成,接下来开始增删改查操作

实现CURD操作

以下代码都是UserTest.java单元测试类中编写

保存用户

@Test
public void test2() {
    // 本次没有给id赋值为保存用户操作
    User user = new User();
    user.setUsername("张三");
    user.setPassword("123456");
    user.setMoney(1000);
    userDao.save(user);
}

即保存用户和更新用户信息都是用的save()方法。

  • 如果执行此方法是对象中存在id属性,即为更新操作会先根据id查询,再更新
  • 如果执行此方法中对象中不存在id属性,即为保存操作

根据id查询用户

使用立即加载

@Test
public void testFindById1() {
        Optional<User> optionalUser = userDao.findById(2);
        // 如果找到返回,找不到则为null
        User user = optionalUser.orElse(null);
        // 如果直接调用get方法找不到就会抛异常
        // User user = optionalUser.get();
        System.out.println(user);
}

使用延迟加载

必须在事务中操作,否则会报错

@Test
@Transactional	// 在事务中操作
public void testFindById2() {
        User user = userDao.getOne(2);
        System.out.println(user);
}

更新用户

@Test
public void testUpdate() {
        // 先查询到该用户
        Optional<User> optionalUser = userDao.findById(4);
        User user = optionalUser.get();
        // 修改用户信息
        user.setMoney(0);
        // 更新操作
	userDao.save(user);
}

如果在事务中的话也可以这样操作

@Test
@Transactional
@Rollback(false)    // 在单元测试中,关闭事务的自动回滚,否则数据不改变
public void testUpdate() {
        // 先查询到该用户
        Optional<User> optionalUser = userDao.findById(4);
        User user = optionalUser.get();
        // 修改用户信息
        user.setMoney(0);
}

就是在事务中修改实体类信息可以自动更新到数据库中,而不用手动调用save()方法

查询用户个数

@Test
public void testCount() {
        long count = userDao.count();
        System.out.println("用户个数:"+count);
}

这没什么好说的,so seay

根据id删除用户

@Test
public void testDelete() {
        userDao.deleteById(3);
}

查询所有用户信息

@Test
public void test1() {
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
}

判断用户是否存在

@Test
public void testExists() {
        // 根据id判断用户是否存在
        // boolean b = userDao.existsById(1);
        
        // 根据用户名判断用户是否存在
        User user = new User();
        user.setUsername("张三三");
        // 构造查询条件
        Example<User> example = Example.of(user);
        boolean b = userDao.exists(example);
        
        System.out.println("该用户是否存在:"+b);
}