Spring Data

202081191941

Spring的数据访问异常体系

SQLException

配置数据源

@Bean
public DataSource dataSource(){
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUsername("root");
    dataSource.setPassword("Root@@715711877");
    dataSource.setUrl("jdbc:mysql:///manage");
    return dataSource;
}

使用profile选择数

@Profile("product")
    @Bean
    public DataSource dataSource(){

        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:h2:~/test");
        return dataSource;
    }

    @Profile("dev")
    @Bean
    public DataSource dataSourceDev(){

        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("Root@@715711877");
        dataSource.setUrl("jdbc:mysql:///manage");
        return dataSource;
    }

在Spring 当中使用JDBC

JDBC模板

JdbcDaoSupport

@Bean
    public JdbcTemplate jdbcTemplate(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSourceDev());
        return jdbcTemplate;
    }
@org.springframework.stereotype.Service
public class Service {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insert(Admin admin){
        jdbcTemplate.update("INSERT INTO admin(username,password) VALUES(?,?)",
                admin.getUsername(),
                admin.getPassword());
    }
}

使用Lambda表达式

jdbcTemplate.query("select * from admin",r->{

    do{
        System.out.println(
                r.getString("username")+"||"+r.getString("password")
        );
    }while (r.next());

});

使用命名参数

public void insert(Admin admin){
    jdbcTemplate.update("INSERT INTO admin(username,password) VALUES(:username,:password)",
            Map.of("username",admin.getUsername(),
                    "password",admin.getPassword()));
}

JPA

需要的一些复杂特性

集成 Hibernate

Spring与JAVA持久化API

@Configuration
@ComponentScan("wang.ismy.spring")
@EnableJpaRepositories(basePackages = "wang.ismy.spring",entityManagerFactoryRef = "entityManagerFactoryBean")
public class Config {

    @Bean
    public DataSource dataSourceDev(){

        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("Root@@715711877");
        dataSource.setUrl("jdbc:mysql:///manage");
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource,
                                                                           JpaVendorAdapter adapter){
        LocalContainerEntityManagerFactoryBean bean =
                new LocalContainerEntityManagerFactoryBean();
        bean.setDataSource(dataSource);
        bean.setJpaVendorAdapter(adapter);
        bean.setPackagesToScan("wang.ismy.spring");
        return bean;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter(){
        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setDatabase(Database.MYSQL);
        adapter.setGenerateDdl(false);
        adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
        return adapter;
    }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(EntityManagerFactory bean, DataSource dataSource) {
        JpaTransactionManager tm =
                new JpaTransactionManager();
        tm.setEntityManagerFactory(bean);
        tm.setDataSource(dataSource);
        return tm;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     https://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/data/jpa
     https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
    <jpa:repositories base-package="wang.ismy.jms" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/>
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="root"/>
        <property name="password" value="123"/>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///ssm"/>
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--扫描实体类-->
        <property name="packagesToScan" value="wang.ismy.jms"/>
        <!--服务提供者-->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>
        <!--服务提供者适配器-->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="generateDdl" value="false" />
                <property name="database" value="MYSQL" />
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
                <property name="showSql" value="true" />
            </bean>
        </property>
        <!--高级特性-->
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>
    </bean>
</beans>

编写基于JPA的Repository

@Data
@Entity
@Table(name = "admin")
public class Admin {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String username;

    private String password;
}
public interface AdminRepository extends JpaRepository<Admin,Integer> { }
adminRepository.findAll();

自定义查询方法

public interface AdminRepository extends JpaRepository<Admin,Integer> { 

    Admin findbyUsername(String username);
}
Keyword Sample JPQL
And findByLastnameAndFirstname ... where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname ... where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstnameIs,findByFirstnameEquals ... where x.firstname = ?1
Between findByStartDateBetween ... where x.startDate between ?1 and ?2
LessThan findByAgeLessThan ... where x.age < ?1
LessThanEqual findByAgeLessThanEqual ... where x.age ⇐ ?1
GreaterThan findByAgeGreaterThan ... where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual ... where x.age >= ?1
After findByStartDateAfter ... where x.startDate > ?1
Before findByStartDateBefore ... where x.startDate < ?1
IsNull findByAgeIsNull ... where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull ... where x.age not null
Like findByFirstnameLike ... where x.firstname like ?1
NotLike findByFirstnameNotLike ... where x.firstname not like ?1
StartingWith findByFirstnameStartingWith ... where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith ... where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining ... where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc ... where x.age = ?1 order by x.lastname desc
Not findByLastnameNot ... where x.lastname <> ?1
In findByAgeIn(Collection ages) ... where x.age in ?1
NotIn findByAgeNotIn(Collection age) ... where x.age not in ?1
TRUE findByActiveTrue() ... where x.active = true
FALSE findByActiveFalse() ... where x.active = false
IgnoreCase findByFirstnameIgnoreCase ... where UPPER(x.firstame) = UPPER(?1)
@Query(value = "SELECT * FROM admin WHERE username = 'admin'",nativeQuery = true)
Admin selfCondition();
@Query("FROM Customer WHERE custName = ?1")
List<Customer> findByJPQL(String name);

// 更新操作
@Query("UPDATE Customer SET custName = ?2 WHERE custId = ?1")
@Modifying
int update(Long id,String name);

动态查询

JpaSpecificationExecutor

Specification

Specification<Customer> spec = (Specification<Customer>) (root/*比较的属性*/, query, cb/*查询方式*/) -> {
    Path<Object> custName = root.get("custName");
    return cb.equal(custName,"老王八");
};
Optional<Customer> one = repository.findOne(spec);

System.out.println(one.get());
Specification<Customer> spec = (Specification<Customer>) (root/*比较的属性*/, query, cb/*查询方式*/) -> {
    Path<Object> custName = root.get("custName");
    Path<Object> custIndustry = root.get("custIndustry");

    var p1 = cb.equal(custName,"老王八");
    var p2 = cb.equal(custIndustry,"隔壁");

    return  cb.and(p1,p2);
};
Specification<Customer> spec = (Specification<Customer>) (root/*比较的属性*/, query, cb/*查询方式*/) -> {
    Path<Object> custName = root.get("custName");

    return cb.like(custName.as(String.class),"%老%");
};
repository.findAll(spec).forEach(System.out::println);
repository.findAll(spec, new Sort(Sort.Direction.DESC,"custId")).forEach(System.out::println);
repository.findAll(PageRequest.of(0,3)).forEach(System.out::println);

Page接口

public interface Page<T> extends Slice<T> {

    static <T> Page<T> empty() {
        return empty(Pageable.unpaged());
    }

    static <T> Page<T> empty(Pageable pageable) {
        return new PageImpl<>(Collections.emptyList(), pageable, 0);
    }

    int getTotalPages();

    long getTotalElements();

    <U> Page<U> map(Function<? super T, ? extends U> converter);
}

多表操作

一对多
@OneToMany(targetEntity = LinkMan.class)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Set<LinkMan> linkMan = new HashSet<>(0);
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
Customer customer = new Customer();
customer.setCustName("20190908");

LinkMan man = new LinkMan();
man.setLkmName("小婊砸");
man.setCustomer(customer);
customerRepository.save(customer);
linkManRepository.save(man);
@OneToMany(mappedBy = "customer")
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
Customer customer = new Customer();
customer.setCustName("20190908");

LinkMan man = new LinkMan();
man.setLkmName("小婊砸");
man.setCustomer(customer);
customer.getLinkMans().add(man);

customerRepository.save(customer);
Optional<Customer> cus = customerRepository.findById(1L);
customerRepository.delete(cus.get());
多对多
@ManyToMany(targetEntity = Role.class)
@JoinTable(name = "user_role",joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")},
        inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")})
private Set<Role> roleSet  = new HashSet<>();
@ManyToMany(targetEntity = User.class)
@JoinTable(name = "user_role",joinColumns ={@JoinColumn(name = "role_id",referencedColumnName = "role_id")},
        inverseJoinColumns =  {@JoinColumn(name = "user_id",referencedColumnName = "user_id")})
private Set<User> userSet = new HashSet<>();
User user = new User();
user.setUsername("老王");

Role role = new Role();
role.setRoleName("隔壁");
user.getRoleSet().add(role);
userDao.save(user);
roleDao.save(role);

对象导航

public enum FetchType {
    LAZY,EAGER
}

缓存数据

启用缓存支持

@Configuration
@ComponentScan("wang.ismy.spring")
@EnableCaching
public class Config {

    @Bean
    public CacheManager cacheManager(){
        return new ConcurrentMapCacheManager();
    }

}

让方法支持缓存

@Cacheable(value = "find",key = "#id")
public String find(Integer id){
    System.out.println("real find");
    return "hello world"+id;
}

在id等于10时不会进行缓存

@Cacheable(value = "find",key = "#id",condition = "#id != 10")
public String find(Integer id){
    System.out.println("real find");
    return "hello world"+id;
}
@CacheEvict(value = "find",key = "#id")
public void remove(Integer id){}

使用xml添加缓存