<!--more-->java
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lwen</groupId> <artifactId>SpringData</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--MySQL Driver--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <!--spring--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.5.RELEASE</version> </dependency> <!--spring data jpa--> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.8.0.RELEASE</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.6.Final</version> </dependency> </dependencies></project>
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!--1 配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="username" value="root"/> <property name="password" value=""/> <property name="url" value="jdbc:mysql://localhost:3306/spring_data"/> </bean> <!--2 配置EntityManagerFactory--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> <property name="packagesToScan" value="com.lwen"/> <property name="jpaProperties"> <props> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!--3 配置事务管理器--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!--4 配置支持注解的事务--> <tx:annotation-driven/> <!--5 配置spring data--> <jpa:repositories base-package="com.lwen" entity-manager-factory-ref="entityManagerFactory"/> <context:component-scan base-package="com.lwen"/></beans>
package com.lwen.entry;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;/** * Student实体类 */@Entitypublic class Student { @Id@GeneratedValue private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; }}
这里注意的一点就是咱们在使用注解的时候必定要注意导入的包,咱们都是导入的javax中的类。mysql
这个东西是SpringData的核心,可是咱们实际去看的时候会发现他是一个空接口,也就是这个一个标记接口。咱们本身的接口必须继承这个接口才会具有查询的功能,因此说咱们的自定的查询器必需要继承这个接口。这个接口是泛型接口也就是咱们须要输入两个参数,第一个就是咱们查询器的类型,针对于那个表进行查询,另一个就是表的Id的类型,这个类型必须是序列化接口的子类型,因此说不能使用基本类型,咱们只能使用包装类型。spring
public interface EmployeeRepository extends Repository<Employee,Integer> { Employee findByName(String name);}
可是咱们还有另一种方式,就是使用注解的方式不用继承这个接口。sql
@RepositoryDefinition(domainClass = Student.class,idClass = Integer.class)public interface StudentRepository {}
这些接口的功能都是很是强大而且实用的咱们在使用的时候就能够直接继承这些接口。数据库
@Query("select o from Employee o where id = (select max(id) from Employee)")Employee getMaxIdEmployee();
@Query("select o from Employee o where name=?1 and age=?2")Employee getByNameAndAge(String name,Integer age);@Query("select o from Employee o where name like %?1%")Employee getByLikeName(String name);
@Query("select o from Employee o where name=:name and age=:age")Employee getByNameAndAge1(@Param("name") String name,@Param("age") Integer age);
@Query(nativeQuery = true,value = "select * from spring_data.employee where name = ?1")void getNative(String name);
在SpringData中使用插删改操做的时候咱们必须定义一个Service层,而后咱们在Service层调用Dao的Repository来更新数据库,接着咱们须要将那个Repository的方法设置为 @Modifying ,最后最重要的就是咱们在Service层的那个方法中写 @Transactional 注解。才能更新成功,因此全部的事务只能出如今 Service 层。可是注意由于咱们的Service没有继承任何的Spring相关的东西咱们要把它放到容器的时候须要使用@Service注解,不然是不行的。apache
@Modifying@Query("update Employee o set o.name=:name where o.id=:id")void update(@Param("id") Integer id,@Param("name") String name);@Servicepublic class EmployeeService { @Autowired EmployeeRepository repository; @Transactional //这个是javax里面的 public void update(){ repository.update(1, "lwenxu"); }}
小提示,不少时候咱们发现有些东西在Spring中有在javax中也有,咱们优先导入Javax中的,若是出现了什么方法没法调用估计就是包导错了。数组
这三个高级的Repository其实是从上到下依次继承的。app
咱们的Repository必需要继承这个接口,而后咱们就有crud的一些操做了。接着咱们须要建立service层,而后再service中使用事务,而且注入咱们的Repository,这里咱们用了一张新的表咱们在bean上指定咱们的表名就是使用@Table(name = "employee_test") 注解。最后进行save操做。dom
@Transactionalpublic void saveAll(List<Employee> employees){ employeeCrudRepository.save(employees);}EmployeeCrudRepository employeeCrudRepository = ctx.getBean(EmployeeCrudRepository.class);ArrayList<Employee> employees = new ArrayList<Employee>();for (int i = 0; i < 100; i++) { employees.add(new Employee(i, "lwen" + i, i));}employeeCrudRepository.save(employees);
他是分页和排序功能。maven
EmployeePageAndSortRepository pageAndSort = ctx.getBean(EmployeePageAndSortRepository.class);//建立一个排序器,是按照id的降续排列的Sort sort = new Sort(new Sort.Order(Sort.Direction.DESC, "id"));//第一个参数是当前的页码他是从0开始的//第二个参数就是每一页的大小//第三个参数是可选参数,传入一个sort,就是按照哪一种方式分页 因为这里用的是降续因此出来的结果应该是 0 在最后一页 99在第一页Pageable pageable = new PageRequest(0, 9, sort);Page<Employee> page = pageAndSort.findAll(pageable);//获取当前页的内容System.out.println(page.getContent());//获取全部的页数System.out.println(page.getTotalPages());
这里吧这个接口单独拿出来讲主要是由于这个接口实际上不是继承自 Repository 这个接口,他的做用从表面上貌似也是看不出来,实际上咱们前面看到咱们能够进行简单的分页,可是那些分页并无一个让咱们传入查询条件的地方,咱们这个接口就是实现了这个功能也就是有条件的分页查询。
jpa接口须要继承 JpaSpecificationExecutor 而后这里就包含了五个方法,分别是 findAll(三个重载) 和 findOne 以及 count 。
而后在使用的时候只调用对应的方法便可,Page<T> findAll(@Nullable Specification<T> var1, Pageable var2); 这个算是里面最复杂的方法了主要是须要传递一个 Specification 对象,这个通常咱们直接传递一个匿名的对象便可,实现后的代码以下:
new Specification<User>() { public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { return criteriaBuilder.gt(root.<Number>get("id"),4); }}
能够看到这个函数式接口里面的第一个参数是 root 这个至关于一个导航器,也就是用它能够获取到咱们实体类中的属性,也就是咱们获取到表的字段,CriteriaQuery 则是能够进行语句的拼装,里面有 where ,groupby 以及having 等方法,进行sql组合的。二最后一个参数就是 CriteriaBuilder 用来建立 Predicate 对象的,也就是生成查询条件对象。
上面的程序生成的最后的条件就是获取id大于4 的全部信息,而后分页展现。
一对一关系这里定义了一个Person对象以及一个IDCard对象
Person类:
@Entity@Table(name="t_person")public class Person{ private int id; private String name; private IDCard card; @OneToOne(mappedBy="person") ---> 指定了OneToOne的关联关系,mappedBy一样指定由对方来进行维护关联关系 public IDCard getCard() { return card; } public void setCard(IDCard card) { this.card = card; } @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
IDCard类:
@Entity@Table(name="t_id_card")public class IDCard{ private int id; private String no; private Person person; @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNo() { return no; } public void setNo(String no) { this.no = no; } @OneToOne ---> OnetoOne指定了一对一的关联关系,一对一中随便指定一方来维护映射关系,这里选择IDCard来进行维护 @JoinColumn(name="pid") ---> 指定外键的名字 pid public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; }}
注意:在判断究竟是谁维护关联关系时,能够经过查看外键,哪一个实体类定义了外键,哪一个类就负责维护关联关系。
这里咱们定义了两个实体类,一个是Cla***oom,一个是Student,这二者是一对多的关联关系。
Cla***oom类:
@Entity@Table(name="t_cla***oom")public class Cla***oom{ private Set<Student> students; public Cla***oom() { students = new HashSet<Student>(); } public void addStudent(Student student) { students.add(student); } @OneToMany(mappedBy="room") ---> OneToMany指定了一对多的关系,mappedBy="room"指定了由多的那一方来维护关联关系,mappedBy指的是多的一方对1的这一方的依赖的属性,(注意:若是没有指定由谁来维护关联关系,则系统会给咱们建立一张中间表) @LazyCollection(LazyCollectionOption.EXTRA) ---> LazyCollection属性设置成EXTRA指定了当若是查询数据的个数时候,只会发出一条 count(*)的语句,提升性能 public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }
Student类:
@Entity@Table(name="t_student")public class Student{ private Cla***oom room; @ManyToOne(fetch=FetchType.LAZY) ---> ManyToOne指定了多对一的关系,fetch=FetchType.LAZY属性表示在多的那一方经过延迟加载的方式加载对象(默认不是延迟加载) @JoinColumn(name="rid") ---> 经过 JoinColumn 的name属性指定了外键的名称 rid (注意:若是咱们不经过JoinColum来指定外键的名称,系统会给咱们声明一个名称) public Cla***oom getRoom() { return room; } public void setRoom(Cla***oom room) { this.room = room; }}
多对多这里一般有两种处理方式,一种是经过创建一张中间表,而后由任一一个多的一方来维护关联关系,另外一种就是将多对多拆分红两个一对多的关联关系
采用中间表的时候由任一一个多的一方来维护关联关系
Teacher类:
@Entity@Table(name="t_teacher")public class Teacher{ private int id; private String name; private Set<Course> courses; public Teacher() { courses = new HashSet<Course>(); } public void addCourse(Course course) { courses.add(course); } @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToMany(mappedBy="teachers") ---> 表示由Course那一方来进行维护 public Set<Course> getCourses() { return courses; } public void setCourses(Set<Course> courses) { this.courses = courses; } }
Course类:
@Entity@Table(name="t_course")public class Course{ private int id; private String name; private Set<Teacher> teachers; public Course() { teachers = new HashSet<Teacher>(); } public void addTeacher(Teacher teacher) { teachers.add(teacher); } @ManyToMany ---> ManyToMany指定多对多的关联关系 @JoinTable(name="t_teacher_course", joinColumns={ @JoinColumn(name="cid")}, inverseJoinColumns={ @JoinColumn(name = "tid") }) ---> 由于多对多之间会经过一张中间表来维护两表直接的关系,因此经过 JoinTable 这个注解来声明,name就是指定了中间表的名字,JoinColumns是一个 @JoinColumn类型的数组,表示的是我这方在对方中的外键名称,我方是Course,因此在对方外键的名称就是 rid,inverseJoinColumns也是一个 @JoinColumn类型的数组,表示的是对方在我这放中的外键名称,对方是Teacher,因此在我方外键的名称就是 tid public Set<Teacher> getTeachers() { return teachers; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; } @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
把以前的ManyToMany拆分红两个One-to-Many的映射
Admin类:
@Entity@Table(name="t_admin")public class Admin{ private int id; private String name; private Set<AdminRole> ars; public Admin() { ars = new HashSet<AdminRole>(); } public void add(AdminRole ar) { ars.add(ar); } @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany(mappedBy="admin") ---> OneToMany关联到了AdminRole这个类,由AdminRole这个类来维护多对一的关系,mappedBy="admin" @LazyCollection(LazyCollectionOption.EXTRA) public Set<AdminRole> getArs() { return ars; } public void setArs(Set<AdminRole> ars) { this.ars = ars; }}
Role类:
@Entity@Table(name="t_role")public class Role{ private int id; private String name; private Set<AdminRole> ars; public Role() { ars = new HashSet<AdminRole>(); } public void add(AdminRole ar) { ars.add(ar); } @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany(mappedBy="role") ---> OneToMany指定了由AdminRole这个类来维护多对一的关联关系,mappedBy="role" @LazyCollection(LazyCollectionOption.EXTRA) public Set<AdminRole> getArs() { return ars; } public void setArs(Set<AdminRole> ars) { this.ars = ars; }}
AdminRole类:
@Entity@Table(name="t_admin_role")public class AdminRole{ private int id; private String name; private Admin admin; private Role role; @Id @GeneratedValue public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToOne ---> ManyToOne关联到Admin @JoinColumn(name="aid") public Admin getAdmin() { return admin; } public void setAdmin(Admin admin) { this.admin = admin; } @ManyToOne ---> @JoinColumn(name="rid") public Role getRole() { return role; } public void setRole(Role role) { this.role = role; }}
小技巧:经过hibernate来进行插入操做的时候,不论是一对多、一对一仍是多对多,都只须要记住一点,在哪一个实体类声明了外键,就由哪一个类来维护关系,在保存数据时,老是先保存的是没有维护关联关系的那一方的数据,后保存维护了关联关系的那一方的数据
两个实体tb_user,tb_role 如今咱们再tb_user或者tb_role中任意一个里面进行维护关系,多对对的状况下咱们须要建立一个中间表来完成这个关系的映射,咱们再tb_user中添加注解@ManyToMany而后再添加一个注解@JoinTable由于咱们是要建立中间表因此要使用这个注解。JoinTable注解中咱们添加以下例子中的内容,joinColumns当前表中的字段在中间表中的字段名称,inverseJoinColumns关联的外键表在中间表中的字段名称
@Entity@Table(name = "tb_user")@SequenceGenerator(name = "tb_user_sq",sequenceName = "tb_user_sqe")public class TbUser extends BaseEntity{/** * 用户名 */private String userName;/** * 登陆名 */private String loginName;/** * 登录密码 */private String passWord;/** * 手机号 */private String telPhone;/** * 一个用户能够有多个角色 */private List<TbRole> tbRoleList=new ArrayList<>();public String getUserName() { return userName;}public void setUserName(String userName) { this.userName = userName;}public String getLoginName() { return loginName;}public void setLoginName(String loginName) { this.loginName = loginName;}public String getPassWord() { return passWord;}public void setPassWord(String passWord) { this.passWord = passWord;}public String getTelPhone() { return telPhone;}public void setTelPhone(String telPhone) { this.telPhone = telPhone;}@Id@Override@GeneratedValue(generator = "tb_user_sq",strategy = GenerationType.SEQUENCE)public Long getId() { return this.id;}@ManyToMany(cascade = CascadeType.REMOVE,fetch = FetchType.LAZY)@JoinTable(name = "tb_user_role",joinColumns = @JoinColumn(name="tb_user_id",referencedColumnName = "id"),inverseJoinColumns = @JoinColumn(name = "tb_role_id",referencedColumnName = "id"))public List<TbRole> getTbRoleList() { return tbRoleList;}public void setTbRoleList(List<TbRole> tbRoleList) { this.tbRoleList = tbRoleList;}}
由于在tb_user中咱们维护了两个表的关系,因此若是咱们在tb_role中若是不想建立关联字段的话就不用添加tbUser的关系字段
@Entity@Table(name = "tb_role")@SequenceGenerator(name = "tb_role_sq",sequenceName = "tb_role_sqe")public class TbRole extends BaseEntity{@Override@Id@GeneratedValue(generator = "tb_role_sq",strategy = GenerationType.SEQUENCE)public Long getId() { return this.id;}private String roleName;@ManyToMany(mappedBy = "tbRoleList")public String getRoleName() { return roleName;}public void setRoleName(String roleName) { this.roleName = roleName;}
若是想要在tb_role中进行维护关联字段的话以下,咱们在字段中添加注解 @ManyToMany而后使用直接属性mappedBy值是当前表在关联表中的字段名称
@Entity@Table(name = "tb_role")@SequenceGenerator(name = "tb_role_sq",sequenceName = "tb_role_sqe")public class TbRole extends BaseEntity{@Override@Id@GeneratedValue(generator = "tb_role_sq",strategy = GenerationType.SEQUENCE)public Long getId() { return this.id;}private String roleName;private List<TbUser> tbUserList=new ArrayList<>();public String getRoleName() { return roleName;}public void setRoleName(String roleName) { this.roleName = roleName;}@ManyToMany(mappedBy = "tbRoleList")public List<TbUser> getTbUserList() { return tbUserList;}public void setTbUserList(List<TbUser> tbUserList) { this.tbUserList = tbUserList;}