引入依賴
這里使用mysql數據庫,所以要引用mysql數據庫連接包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
添加配置
在application.yml文件添加數據庫連接配置及jpa配置
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot_1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true username: root password: 123456 jpa: properties: hibernate: hbm2ddl: auto: update dialect: org.hibernate.dialect.MySQL5InnoDBDialect format_sql: true show-sql: true
實體類
a)組織
@Entity @Table(name="t_organization") public class Organization { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable=false) private String name; @Column(nullable=false) private String code; @OneToMany(mappedBy="organization",cascade=CascadeType.REMOVE,fetch=FetchType.EAGER) private List<User> userList; public Organization(){}; public Organization(String name,String code,List<User> userList){ this.name = name; this.code = code; this.userList = userList; }
b)用戶
@Entity @Table(name="t_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private String sex; @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST}) @JoinColumn(name="orgId") @JsonIgnore private Organization organization; @ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST}) @JoinTable(name="t_user_role",joinColumns={@JoinColumn(name="userId")}, inverseJoinColumns={@JoinColumn(name="roleId")} ) private List<Role> roleList; public User(){}; public User(String name,String sex,Organization organization){ this.name = name; this.sex = sex; this.organization = organization; }
c)角色
@Entity public class Role { @Id @GeneratedValue private Long id; @Column private String name; @ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST}) @JoinTable(name="t_user_role",joinColumns={@JoinColumn(name="roleId")}, inverseJoinColumns={@JoinColumn(name="userId")} ) @JsonIgnore private List<User> userList; @ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST}) @JoinTable(name="t_role_privilege",joinColumns={@JoinColumn(name="roleId")}, inverseJoinColumns={@JoinColumn(name="privilegeId")}) private List<Privilege> privilegeList; public Role(){}; public Role(String name,List<User> userList, List<Privilege> privilegeList){ this.name = name; this.userList = userList; this.privilegeList = privilegeList; }
d)權限
@Entity public class Privilege { @Id @GeneratedValue private Long id; @Column private String name; @ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST}) @JoinTable(name="t_role_privilege",joinColumns={@JoinColumn(name="privilegeId")}, inverseJoinColumns={@JoinColumn(name="roleId")}) @JsonIgnore private List<Role> roleList; public Privilege(){}; public Privilege(String name,List<Role> roleList){ this.name = name; this.roleList = roleList; }
級聯
a)cascade:級聯操作權限
PERSIST 級聯保存
REMOVE 級聯刪除
MERGE 級聯更新
DETACH 級聯游離,要想刪除某一條學生信息,但學生的id在成績表中作為外鍵,無法直接刪除
REFRESH 級聯刷新 與MERGE 好像沒什么區別
ALL 上面所有的結合,慎用
b)fetch:設置關聯對象的加載方式
EAGER 立即加載
LAZY 延遲加載,需要用到的時候再加載
關聯對象
a)OneToMany
一對多,一對多一般不維護關系表字段,所以在這端添加 mappedBy=“mappedBy值” , mappedBy值是多端對象指向一端的屬性值,mappedBy與JoinColumn、JoinTable互斥。因為JoinColumn、JoinTable表示這一端維護這外鍵或中間表
b)ManyToOne
多對一,一般在這端添加外鍵,外鍵對應的字段 JoinColumn(name="外鍵") ,外鍵由這端進行維護
c)ManyToMany
多對多,一般添加一個中間表, @JoinTable(name="t_user_role",joinColumns={@JoinColumn(name="自己的ID字段")},inverseJoinColumns={@JoinColumn(name="另一端的ID字段")} )
接口編寫
編寫一個用戶接口
public interface UserRepository extends JpaRepository<User, Long>{ List<User> findByName(String name); List<User> findByNameLike(String name);
在要使用用戶接口的地主直接引用即可
@Resource
private UserRepository userRepository;
命名查詢
下表描述了JPA支持的關鍵字以及包含該關鍵字的JPA命名查詢方法:
關鍵字 |
示例 |
SQL |
And |
findByLastnameAndFirstname |
… where x.lastname = ?1 and x.firstname = ?2 |
Or |
findByLastnameOrFirstname |
… where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals |
findByFirstname,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<Age> ages) |
… where x.age in ?1 |
NotIn |
findByAgeNotIn(Collection<Age> ages) |
… 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(? |
Query查詢
a)原生sql查詢,nativeQuery = true
@Query(value="select * from t_user u where u.name =?1",nativeQuery = true) List<User> queryBySql(String name);
b)hql查詢
@Query(value="select u from User u where u.name =?1",nativeQuery = false) List<User> queryByHql(String name);
c)使用命名參數傳參
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname") User findByLastnameOrFirstname(@Param("lastname")String lastname,@Param("firstname")String firstname);
d)返回的不是實體對象
如果返回的不是實體對象,則可以先建一個dto返回類對象UserVo,把查詢的結果映射到實體類上
@Query(value="select new com.ouou.vo.UserVo(u.id,u.name,u.sex) from User u where u.name =?1",nativeQuery = false) List<UserVo> queryByHqlUserVo(String name);
或返回一個數組對象,然后在代碼里進行組裝提取
@Query(value="select u.id,u.name,u.sex from User u where u.name =?1",nativeQuery = false) List<Object[]> queryByHqlObject(String name);
分頁查詢
編寫分頁接口
Page<User> findByNameLike(String name,Pageable pageable); @Query(value="select new com.ouou.vo.UserVo(u.id,u.name,u.sex) from User u where u.name like ?1",nativeQuery = false) Page<UserVo> queryByHqlUserVoPage(String name,Pageable pageable);
a)通過參數生成Pageable對象
Pageable
定義了很多方法,但其核心的信息只有兩個:一是分頁的信息(page、size),二是排序的信息。Spring Data Jpa提供了PageRequest
的具體實現,Spring MVC提供了對Spring Data JPA非常好的支持,我們只提供分頁以及排序信息即可:
@RequestMapping(value = "/params", method=RequestMethod.GET) public Page<User> getEntryByParams(Integer page,Integer size) { Sort sort = new Sort(Direction.DESC, "id"); Pageable pageable = new PageRequest(page, size, sort); return userRepository.findByNameLike("姓名",pageable); }
在這里,我們通過參數獲得分頁的信息,並通過Sort
以及Direction
告訴pageable需要通過id逆序排列
b)直接獲取Pageable對象
@RequestMapping(value = "/params", method=RequestMethod.GET) public Page<User> getEntryByPageable(@PageableDefault(value = 15, sort = { "id" }, direction = Sort.Direction.DESC) Pageable pageable) { returnuserRepository.findByNameLike("姓名",pageable); }
我們可以看到,我們只需要在方法的參數中直接定義一個pageable類型的參數,當Spring發現這個參數時,Spring會自動的根據request的參數來組裝該pageable對象,Spring支持的request參數如下:
- page,第幾頁,從0開始,默認為第0頁
- size,每一頁的大小,默認為20
- sort,排序相關的信息,以
property,property(,ASC|DESC)
的方式組織,例如sort=firstname&sort=lastname,desc
表示在按firstname正序排列基礎上按lastname倒序排列
這樣,我們就可以通過url的參數來進行多樣化、個性化的查詢,而不需要為每一種情況來寫不同的方法了。
通過url來定制pageable很方便,但唯一的缺點是不太美觀,因此我們需要為pageable設置一個默認配置,這樣很多情況下我們都能夠通過一個簡潔的url來獲取信息了。
Spring提供了@PageableDefault
幫助我們個性化的設置pageable的默認配置。例如@PageableDefault(value = 15, sort = { "id" }, direction = Sort.Direction.DESC)
表示默認情況下我們按照id倒序排列,每一頁的大小為15
事務
在service 或 controller類上或方法上添加注解 @Transactional即可。注意:如果service類和controller類上都有@Transactional,則controller類上的事務注解生效,service上的事務注解不生效