Spring Data

202081191941

Spring的数据访问异常体系

SQLException

配置数据源

@Beanpublic 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.Servicepublic 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);}
KeywordSampleJPQL
AndfindByLastnameAndFirstname... where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname... where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs,findByFirstnameEquals... where x.firstname = ?1
BetweenfindByStartDateBetween... where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan... where x.age < ?1
LessThanEqualfindByAgeLessThanEqual... where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan... where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual... where x.age >= ?1
AfterfindByStartDateAfter... where x.startDate > ?1
BeforefindByStartDateBefore... where x.startDate < ?1
IsNullfindByAgeIsNull... where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull... where x.age not null
LikefindByFirstnameLike... where x.firstname like ?1
NotLikefindByFirstnameNotLike... where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith... where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith... where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining... where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc... where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot... where x.lastname <> ?1
InfindByAgeIn(Collection ages)... where x.age in ?1
NotInfindByAgeNotIn(Collection age)... where x.age not in ?1
TRUEfindByActiveTrue()... where x.active = true
FALSEfindByActiveFalse()... where x.active = false
IgnoreCasefindByFirstnameIgnoreCase... 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")@Modifyingint 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")@EnableCachingpublic 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添加缓存