搭建第一个SpringDataJPA工程
1.创建Java工程
2.导入jar包或者maven坐标
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
<hibernate.version>5.0.7.Final</hibernate.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<c3p0.version>0.9.1.2</c3p0.version>
<mysql.version>5.1.6</mysql.version>
</properties>
<dependencies>
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<!-- spring beg -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring end -->
<!-- hibernate beg -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!-- hibernate end -->
<!-- c3p0 beg -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- c3p0 end -->
<!-- log end -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<!-- el beg 使用spring data jpa 必须引入 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<!-- el end -->
</dependencies>
3.创建核心配置文件beans.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!--开启注解-->
<context:annotation-config/>
<!--开启组件扫描-->
<context:component-scan base-package="com.zx"></context:component-scan>
<!--开启切面注解-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan" value="com.zx.entity"></property>
<!--底层Hibernate实现厂商-->
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
</property>
<!--JPA的供应商适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="MYSQL" />
<!--方言-->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<property name="showSql" value="true" />
</bean>
</property>
<!--注入JPA的配置信息-->
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<jpa:repositories base-package="com.zx.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
<!--aop相关XML配置-->
<!--<bean id="myAspect_xml" class="com.zx.aop.MyAspect_XML"></bean>
<aop:config>
<aop:aspect id="myaspect" ref="myAspect_xml">
<aop:pointcut id="pointcut" expression="execution(public * com.zx.service..*.*(..))"/>
<aop:before method="test01" pointcut-ref="pointcut"></aop:before>
</aop:aspect>
</aop:config>-->
</beans>
4.创建实体类
/*
@Entity 实体类映射
@Table 映射的表格
name 表格名称
@Id 主键
@GeneratedValue 主键生成策略
IDENTITY 主键自动递增(适用于底层支持自动递增的数据库)
SEQUENCE 序列(适用于Oracle)
AUTO 自动创建第三张表维护主键的下一个值
TABLE 创建第三张表维护主键的下一个值
*/
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
5.创建dao层
/**
* 创建符合SpringDataJPA规范的接口dao
* JpaRepository<实体类类型,主键类型>:用来完成基本CRUD操作
* JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作)
*/
public interface XXXDao extends JpaRepository<XXX,实体类中主键类型>, JpaSpecificationExecutor<XXX>
6.测试
Spring提供的单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:beans.xml")
public class UserDaoTest {
@Resource
private UserDao userDao;
@Test
public void Test(){
User user=new User("李四","45612563");
userDao.save(user);
}
//删除
@Test
public void Test01(){
//userDao.delete(5);
User user=new User();
user.setId(3);
userDao.delete(user);
}
}
7.基本增删改查操作
增加:save(对象)
如果对象中没有id,则执行添加操作
如果有id值,需要判断id在数据库中是否存在,如果不存在,则执行添加操作
如果存在,则执行修改操作
删除:delete(主键)
delete(带有数据库中存在的id的对象)
修改:save(带有数据库中存在的id的对象)
查询某一个:
findOne(主键) 不管是否使用到对象,都会发送sql语句,及时加载
getOne(主键) 什么时候使用对象,什么时候发送sql语句,懒加载
直接使用对象报错no session问题
解决办法:在方法上追加事务注解@Transactional
8.执行原理
通过jdk动态代理技术创建JpaRepository与JpaSpecificationExecutor子实现类SimpleJpaRepository在SimpleJpaRepository类中将findOne方法重写
9.查询机制
9.1查询某一个
findOne(主键) 不管是否使用到对象,都会发送sql语句,及时加载
getOne(主键) 什么时候使用对象,什么时候发送sql语句,懒加载
直接使用对象报错no session问题
解决办法:在方法上追加事务注解@Transactional
*findOne(动态条件Specification)
//查询
@Test
public void Test02(){
List<User> list = userDao.findAll();
System.out.println(list);
User user = userDao.findOne(4);
System.out.println(user);
}
@Test
@Transactional
public void Test03(){
User user = userDao.getOne(4);
System.out.println(user);
}
9.2查询所有
findAll() 查询所有
findAll(排序Sort) 查询所有并排序
Sort sort = new Sort(Sort.Direction.DESC,"id");
List<User> users = userDao.findAll(sort);
findAll(分页) 查询所有并分页
Pageable pageable = new PageRequest(1,2);
Page<User> page = userDao.findAll(pageable);
System.out.println(page.getContent());
9.3JPQL查询
使用JPQL语句查询所有 @Query(“JPQL语句”)
@Query("from User")
List<User> testAll();
@Query("from User where id=?1")
User testId(int id);
@Query("from User where username=?1 and password=?2 ")
User testUsernameAndPassword(String username,String password);
9.4SQL查询
@Query(value = "select * from t_user",nativeQuery = true)
List<User> testAllSQL();
不管JPQL还是SQL,在@Query(“增删改语句”),但是需要追加@Modifying,在测试方法上标明事务注解以及不回滚注解@Transactional @Rollback(value = false)
@Query("delete from User where password=?")
@Modifying
//通知Spring Data 这是一个DELETE或UPDATE操作。
void deleteTest(String password);
@Test
@Transactional
@Rollback(value = false)
public void test10(){
userDao.deleteTest("123123");
}
9.5特殊方法命名查询
findBy开头+属性名称的首字母大写
User findByPasswordAndUsername(String password,String username);
9.6动态查询
findAll(动态条件Specification) 动态查询
//单条件动态查询
@Test
public void test12(){
final Specification<User> spec=new Specification<User>(){
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//获取要查询的字段
Path<Object> username = root.get("username");
//构造条件
Predicate predicate = criteriaBuilder.equal(username, "admin");
return predicate;
}
};
List<User> list = userDao.findAll(spec);
System.out.println(list);
}
//多条件动态查询
@Test
public void test13(){
final Specification<User> spec=new Specification<User>(){
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//获取要查询的字段
Path<Object> username = root.get("username");
Path<Object> password = root.get("password");
//构造条件
Predicate predicate1 = criteriaBuilder.equal(username, "admin");
Predicate predicate2 = criteriaBuilder.equal(password, "456789");
Predicate predicate = criteriaBuilder.and(predicate1, predicate2);
return predicate;
}
};
List<User> list = userDao.findAll(spec);
System.out.println(list);
}
//动态模糊查询
@Test
public void test14(){
Specification<User> specification=new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> username = root.get("username");
Predicate predicate = criteriaBuilder.like(username.as(String.class), "%adm%");
return predicate;
}
};
List<User> users = userDao.findAll(specification);
System.out.println(users);
}
findAll(动态条件Specification,分页) 动态查询并分页
Pageable pageable=new PageRequest(0,2);
Page<User> page = userDao.findAll(spec, pageable);
System.out.println(page.getContent());
findAll(动态条件Specification,排序) 动态查询并排序
@Test
public void test14(){
Specification<User> specification=new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> username = root.get("username");
Predicate predicate = criteriaBuilder.like(username.as(String.class), "%adm%");
return predicate;
}
};
Sort sort=new Sort(Sort.Direction.DESC,"id");
List<User> users = userDao.findAll(specification,sort);
System.out.println(users);
}
10.关联对象
10.1多对一和一对多
/*
@ManyToOne 多对一
targetEntity 对方实体字节码
@JoinColumn 添加外键
name 外键名称
referencedColumnName 外键引用方的名称
*/
@Entity
@Table(name = "t_person")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
@ManyToOne(targetEntity = Group.class)
@JoinColumn(name = "gid",referencedColumnName = "id")
private Group group;
/*
@OneToMany 一对多
mappedBy 对方维护外键关系
*/
@Entity
@Table(name = "T_group")
public class Group {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String gname;
@OneToMany(mappedBy = "group")
private List<Person> persons;
10.2测试过程
需要绑定外键关系,一般情况下,是多方设置一方需要先保存一(group)方,再保存多方
如果先保存多方,再保存一方的时候,需要追加事务注解以及关闭回滚操作
@Test
@Transactional
@Rollback(value = false)
public void add(){
Person person=new Person("admin","admin");
Group group=new Group("一组");
person.setGroup(group);//一方
personDao.save(person);
groupDao.save(group);
}
级联添加
@OneToMany(mappedBy = "group",cascade = CascadeType.PERSIST)
@Test
public void test(){
Person person=new Person("lisi","lisi");
Person person1=new Person("zhangsan","zhangsan");
Group group=new Group("二组");
person.setGroup(group);
person1.setGroup(group);
List<Person> persons=new ArrayList<>();
persons.add(person);
persons.add(person1);
group.setPersons(persons);
groupDao.save(group);
}
级联删除
@OneToMany(mappedBy = "group",cascade = CascadeType.REMOVE)
@Test
public void del(){
groupDao.delete(1);
}
级联更新
@OneToMany(mappedBy = "group",fetch = FetchType.EAGER,cascade = CascadeType.MERGE)
@Test
@Transactional
@Rollback(value = false)
public void update(){
Group group=groupDao.findOne(4);
List<Person> persons = group.getPersons();
group.setGname("one");
persons.get(0).setUsername("aaa");
groupDao.save(group);
}
级联查询
通过一方查询多方,会报错懒加载问题,解决办法:
方式一:追加事务@Transactional 发送两条sql语句
@Test
@Transactional
public void find(){
Group group=groupDao.findOne(4);
System.out.println(group);
System.out.println(group.getPersons());
}
方式二:关闭懒加载或者开启及时加载(抓取策略)
@OneToMany(mappedBy = “group”,fetch = FetchType.EAGER) 发送一条sql语句
10.3多对多
/*
@ManyToMany 多对多
targetEntity 对方字节文件
@JoinTable 加入中间表
name 中间表名称
joinColumns 本表在中间表中的配置
@JoinColumn 配置外键
name 外键名称
referencedColumnName 外键引用方的名称
inverseJoinColumns 对方表在中间表中的配置
@JoinColumn 配置外键
name 外键名称
referencedColumnName 外键引用方的名称
*/
student
@Entity
@Table(name = "t_student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int sid;
private String sname;
@ManyToMany(targetEntity = Teacher.class,fetch = FetchType.EAGER)
@JoinTable(name = "t_student_teacher",
joinColumns = {@JoinColumn(name = "sid",referencedColumnName = "sid")},
inverseJoinColumns = {@JoinColumn(name="tid",referencedColumnName =
"tid")})
private List<Teacher> teachers;
public Student() {
}
teacher
@Entity
@Table(name = "t_teacher")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int tid;
private String tname;
@ManyToMany(mappedBy = "teachers")
private List<Student> students;
public Teacher() {
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:beans.xml")
public class ManyToMany {
@Autowired
private StudentDao studentDao;
@Autowired
private TeacherDao teacherDao;
@Test
public void add(){
Student student1=new Student("张三");
Student student2=new Student("李四");
Teacher teacher=new Teacher("李老师");
List<Teacher> teachers=new ArrayList<>();
teachers.add(teacher);
student1.setTeachers(teachers);
student2.setTeachers(teachers);
teacherDao.save(teacher);
studentDao.save(student1);
studentDao.save(student2);
}