zoukankan      html  css  js  c++  java
  • Spring框架学习(四)SpringData

    说是SpringData,其实其中包含了太多内容,同样开始看的一头雾水,其实现在还是有很多不了解的地方。

    官方文档还是讲的不错的,一开始看会比较迷茫,但是稍微看一些以后,有些疑问在里面有说明。这是地址

    这里都是基于SpringBoot的自动配置进行的,所以大部分配置比较简单。

    spring jdbc

    jdbc是java原有的数据访问组件,创建连接、创建查询、执行查询、结果通过ResultSet逐个读取转换。

    当前面加上spring名头后,指的是spring的jdbc框架(或者叫模块?)。通过spring-boot-starter-data-jdbc依赖,使spring程序中可以得到一个注入得jdbctemplate对象,而不再依赖DriverMaanger,而且简化了访问方法。当然底层还是用的jdbc

    当然jdbc并非ORM,因为还是面向与sql执行结果得,结果也需要手工转换为实体类(或者通过RowMapper)。

    配置

    配置比较少,基本使用只要配置DataSource就好了。

    其实DataSource并非jdbc的概念,它代表一个数据库的配置,后面SpringJPA也要用到。

    同样有代码和文件的配置方式,这是使用文件的方式进行配置的:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    	<bean name="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="url"
    			value="jdbc:mysql://localhost:3306/testdb?serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8" />
    		<property name="username" value="root" />
    		<property name="password" value="123456" />
    	</bean>
    </beans>
    

    对于这个配置文件多说两句:

    1. 网上教程需要配置driver这个property,比如指向mysql,但是我用的时候,会有日志说不用配,会自动加载,我试了的确如此
    2. 注意连接字符串里的serverTimezone=Asia/Shanghai这个配置,可能是jdbc版本原因,如果不加这个,数据库连接会报时区不对的错误。

    注意在springboot入口,需要添加对这个配置文件的依赖:

    @SpringBootApplication
    @ImportResource("classpath:jdbc-config.xml")
    public class App {
    	public static void main(String[] args) {
    		new SpringApplicationBuilder(App.class).run(args);
    	}
    }
    

    也可以使用代码的方式,两者相同:

        @Bean
        public DataSource getDataSource() {
            DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
            dataSourceBuilder.url("jdbc:mysql://localhost:3306/testdb?serverTimezone=Asia/Shanghai");
            dataSourceBuilder.username("root");
            dataSourceBuilder.password("123456");
            return dataSourceBuilder.build();
        }
    

    配置就是这样,很简单

    使用jdbcTemplate

    repository需要通过注解标记,主要为了

    • 被识别为bean
    • 特殊处理其中抛出的数据库异常
    @Repository
    public class EmployeeRepository {
    	@Autowired
    	NamedParameterJdbcTemplate jdbc;
    
    	public void createEmployee(Employee employee) {
    		jdbc.execute("insert into employees (name,email) values (:name,:email)",
    				new BeanPropertySqlParameterSource(employee), (pc) -> {
    					pc.execute();
    					return null;
    				});
    	}
    
    	public void updateEmployee(long id, Employee employee) {
    		jdbc.update("update employees set name=:name, email=:email where id=:id", new MapSqlParameterSource()
    				.addValue("id", id).addValue("name", employee.getName()).addValue("email", employee.getEmail()));
    	}
    
    	public Employee getEmployee(long id) {
    		return jdbc.queryForObject("select * from employees where id=:id", new MapSqlParameterSource("id", id),
    				new EmployeeRowMapeer());
    	}
    }
    
    class EmployeeRowMapeer implements RowMapper<Employee> {
    	@Override
    	public Employee mapRow(ResultSet rs, int rownumber) throws SQLException {
    		Employee e = new Employee();
    		e.setId(rs.getInt(1));
    		e.setName(rs.getString(2));
    		e.setEmail(rs.getString(3));
    		return e;
    	}
    }
    

    这里

    1. 注册了NamedParameterJdbcTemplate,相比普通的JdbcTemplate,可以支持MapSqlParameterSourceBeanPropertySqlParameterSource两个类作为结构化参数传入
    2. 使用了update/execute等方法执行数据库操作
    3. 定义了RowMapper来转换返回结果到实体类

    spring jpa

    前言

    有一种说法是spring jpa下面使用了jdbc,不过我没有找到相关的资料。

    在spring jpa之前,同样的也有一个JPA,它时操作EnitityManager来进行ORM操作,同样有类似JDBC的复杂性,而SpringJPA封装了这个类到Repository中,使用方便了。

    不过在了解SpringJPA前,JPA也有一些概念,比如JPA有一个需要通过EntityManagerFactory创建EntityManager,而EntityManager内部由各种实现(比如hibernate)维护一个Persistance Context,里面跟踪了所有的Entity情况。

    spring jpa定义了一套接口规范,具体有一些实现组件,比如spring默认的似乎是hibernate。

    SpringJPA在使用上以Repository为基础,有下面这些内容(部分)。

    SpringJPA使用spring-boot-starter-data-jpa作为开始依赖。

    实体类

    • 通过@Entity定义实体类,所以JPA是一种ORM框架,可以将实体与数据库表关联
    @Entity
    @Table(name = "employees")
    public class Employee {
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	long id;
    	String name;
    	String email;
      //省略getter setter
    }
    

    Repository类

    定义了Repository接口,接口有两个模板参数,一个是实体类,一个是实体类的id类型,通过这个信息,找到Repository使用的表。

    public interface Repository<T, ID> {
    }
    

    直接定义接口名称,Repository可以自动生成实现,比如定义List<Employee> findByName(String name);,就不用写方法实现,JPA内部会自动生成查询方法,并将参数传入

    public interface EmployeeRepository extends Repository<Employee, Long> {
    
    	List<Employee> findByName(String name);
    }
    

    方法里传入的SortPageable参数也能被正确转换为所需的排序或者分页信息。

    预定义的Repository

    提供了类似CrudRepository接口,定义了常用的findAll,count,findById等方法;提供了PagingAndSortingRepository,进一步增加了携带SortPageable的相关方法。

    应用的Repository集成这些类,常用的CRUD可以不用定义直接使用。

    public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long> {}
    
    

    使用时可以直接使用save方法:

    
    	@Autowired
    	EmployeeRepository repo;
    
    	@Override
    	public void createEmployee(Employee employee) {
    		repo.save(employee);
    
    	}
    

    自定义方法实现:

    当通过名称实现不满足要求时,支持JPQLSQL自定义方法。

    JPQL

    JPQL是JPA定义的SQL,会在Repository初始化的时候就进行预处理,如果其中有错误,这时就会报错。

    这是通过JPQL查询的方法:

    	@Query("select e from #{#entityName} e where name like %?1%")
    	List<Employee> CustomQuery(String name, Pageable page);
    
    • 参数可以通过位置符号?1替代,这里被替换为了name
    • #{#entityName}被自动替代为实体名字,这样不用写死在代码中
    • Pageable参数可以被SpringJPA自动识别并加入到最后的查询中
    • 注意这是一个Like语句,百分号周围没有加单引号,如果加了就得不到想要的结果了,推测应该是ORM框架自动加的
    原生sql

    同样可以通过原生SQL:

    	@Query(value = "SELECT * FROM #{#entityName} WHERE name like %:name%", nativeQuery = true)
    	List<Employee> NativeQuery(@Param("name") String name);
    

    这里通过nativeQuery标识标明sql被数据库直接执行。
    在此之前,同样可以进行参数替换,这里使用了命名参数的方式@Param("name") 对应到sql中的:name

    实体名称替换( #{#entityName})同样有效。

    同样也需要注意

    EntityManager

    可以回到java JPA中EntityManager中的方法,对比可以看出来SpringJPA帮忙省略的细节。

    注意这里扩展的方法需要实现,所以额外定义一个Cusom接口和Impl类

    public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>, EmployeeRepositoryCustom {
    
    //	@Query(value = "SELECT * FROM #{#entityName} WHERE name like %:name%", nativeQuery = true)
    //	List<Employee> NativeQuery(@Param("name") String name);
    }
    
    interface EmployeeRepositoryCustom {
    
    	public List<Employee> NativeQuery(String name);
    }
    
    class EmployeeRepositoryImpl implements EmployeeRepositoryCustom {
    
    	@PersistenceContext
    	EntityManager entityManager;
    
    	public List<Employee> NativeQuery(String name) {
    		javax.persistence.Query query = entityManager.createNativeQuery("select * from employees where name like ?1",
    				Employee.class);
    		query.setParameter(1, name + "%");
    		List<Employee> list = query.getResultList();
    		return list;
    	}
    }
    

    相比较之前的Native SQL方式,这里同样是创建原生SQL,只是代码要复杂许多,因为暴露出来的接口EmployeeRepository还需要扩展自自定义的接口EmployeeRepositoryCustom

  • 相关阅读:
    codevs 2632 非常好友
    codevs 1213 解的个数
    codevs 2751 军训分批
    codevs 1519 过路费
    codevs 1503 愚蠢的宠物
    codevs 2639 约会计划
    codevs 3369 膜拜
    codevs 3135 River Hopscotch
    数论模板
    JXOJ 9.7 NOIP 放松模拟赛 总结
  • 原文地址:https://www.cnblogs.com/mosakashaka/p/12609127.html
Copyright © 2011-2022 走看看