使用idea搭建SpringBoot+Spring Data jpa項目(實現獲取數據庫數據顯示在頁面中)

搭建SpringBoot準備

  • javaweb基礎
  • idea使用基礎
  • maven使用基礎

開始搭建SpringBoot項目

  1. 創建springboot
    在這裏插入圖片描述
  2. 設置Group、Artifact、Packaging
    在這裏插入圖片描述
  3. 選擇web及SpringBoot版本
    在這裏插入圖片描述
  4. 配置application.properites
    SpringBoot默認情況下沒有項目名和端口號需要我們在application.properites文件內配置項目和端口號
    再加上mysql配置
server.servlet.path=/evaluate
server.port=8081

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql:///evaluate?characterEncoding=utf-8&useSSL=false
spring.jpa.show-sql=true
  1. 編寫實體類類
    因爲要使用jpa,所以實體類中屬性命名方式要和數據中的表按照規則對應

jpa簡介:

JPA是Java Persistence API的簡稱,中文名Java持久層API,是一種規範,我們可以使用hibernate來實現這規範。
JPQL查詢語言:通過面向對象而非面向數據庫的查詢語言查詢數據,避免程序的SQL語句緊密耦合。
如:from Student s where s.name = ?
語法和SQL差別不大。
String Data jpa是對hibernate實現的jpa規範進行了輕量級封裝。

String Data Jpa識別實體類

@Entity 識別爲實體類
@id 識別爲主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY) 識別爲自增
規則如下:
1.命名相同
2.如果數據中有下劃線,下劃線後面字母大寫
即:實體類:danYuan < ----- >數據庫表字段:dan_yuan
3.如果不使用它的自動對應配置,可以直接配置
@Table(name = “表名”)
@Column(name=“字段名”)

@Entity
@Table(name = "danyuan")
public class Danyuan {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="danyuan_id")
    private Integer danyuanId;
    @Column(name="name")
    private String name;
    @Column(name="dizhi")
    private String dizhi;
    @Column(name="code")
    private String code;
    @Column(name="parent_code")
    private String parentCode;
    //get、set方法省略
    }

如果不匹配的話會報錯
在這裏插入圖片描述
6. DanyuanRepository接口
需要繼承JpaRepository(簡單增刪改查)
JpaRepository<實體類,主鍵類型>

public interface DanyuanRepository extends JpaRepository<Danyuan,Integer> {

    List<Danyuan> findByParentCode(String code);

}

  1. service層
public interface DanyuanService {
    List<Danyuan> findByParentCode(String code);
}

繼承JPaSpecificationExecutor複雜操作(這裏不需要)
JPaSpecificationExecutor<實體類>
接口約定命名規則
在這裏插入圖片描述
在這裏插入圖片描述

@Service
public class DanyuanServiceImpl implements DanyuanService {

   @Autowired
   private DanyuanRepository danyuanRepository;

    @Override
    public List<Danyuan> findByParentCode(String code) {
        return danyuanRepository.findByParentCode(code);
    }
}
  1. Controller
@Controller
@RequestMapping("/danyuan")
public class DanyuanController {

    @Autowired
    private DanyuanService danyuanService;

    @RequestMapping("/findByParentCode")
    @ResponseBody
    public List<Danyuan> findByParentCode(@RequestParam("parentCode") String parentCode){
        return danyuanService.findByParentCode(parentCode);
    }
}
  1. 已經簡單實現獲取數據庫數據顯示在頁面中
    10.效果展示
    在這裏插入圖片描述

junit測試

@RunWith(SpringRunner.class)
@SpringBootTest(class= 啓動類.class)
public class test01{
	@Test
	public void test(){
	}
}

補充:

spring data jpa 中的dao層實現原理是通過jdk動態代理找到SimpleJapRepository動態代理對象,SimpleJapRepository實現了JapRepository接口,調用SimpleJapRepository中方法來實現我們寫的dao實現類,其中SimpleJapRepository是使用jpa規範中EntityManager方法。jpa規範通過hibernate來實現jpa語法,hibernate通過封裝的jdbc生成sql來在數據庫中執行SQL語句。
找到一個圖很好的寫出來了,該圖是描述的ssm項目,原理一致
在這裏插入圖片描述

spring data jpa 使用jpql語句(nativeQuery參數爲false)

在自定義方法中加@Query註解

@Query(value="from Danyuan where title =  ?1",nativeQuery=false)
public Danyuan findJpql(String title)
spring data jpa 使用sql語句(nativeQuery參數爲true)
@Query(value="select * from danyuan where title =  ?1",nativeQuery=true)
public Danyuan findJpql(String title)

自定義SQL高效更新(一般是全表更新,效率不如單字段更新)

@Modifying
@Transactional(readOnly = false) //@odifying需要寫事務支持
@Query(value="UPDATE Danyuan SET name=:name WHERE id=:id”,nativeQuery=true)
public Danyuan updateName(@Param("name") String name,@Param("id") String id)

返回map集

在JPA 2.0 中我們可以使用entityManager.createNativeQuery()來執行原生的SQL語句。 但當我們查詢結果沒有對應實體類時,query.getResultList()返回的是一個List<Object[]>。也就是說每行的數據被作爲一個對象數組返回。
JPA的API中並沒有提供返回map集。其實很多JPA的底層實現都是支持返回Map對象的如:
Hibernate的.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
綜上所述:

Query query = entityManager.createNativeQuery(sql);
query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List<Map<String, Object>> resutl = query.getResultList();

這裏需要注意的是, 用Map肯定要比用Object數組來的效率低。所以你要看性能下降是否在可接受範圍內。

JpaSpecificationExecutor使用 specifications實現類動態查詢

源碼

public interface JpaSpecificationExecutor<T> {

	/**
	 *  查詢單個對象
	 */
	T findOne(Specification<T> spec);

	/**
	 * 查詢列表 
	 */
	List<T> findAll(Specification<T> spec);
	/**
	 * 分頁  pageable分頁參數
	 */
	Page<T> findAll(Specification<T> spec, Pageable pageable);

	/**
	 * 查詢列表 ,sort排序 new Sort(Sort.Direction.DESC,"num");
	 */
	List<T> findAll(Specification<T> spec, Sort sort);

	/**
	 * 統計
	 */
	long count(Specification<T> spec);
}

specification:查詢條件
自定義specification實現類
Predicate toPredicate(Root root, CriteriaQuery<?> query, CriteriaBuilder cb);封裝條件
root:查詢的根對象(查詢的任何屬性都可以從根對象中獲取)
CriteriaQuery:頂層查詢對象,自定義查詢方式(一般不用)
CriterriaBuilder: 查詢的構造器,封裝了很多的查詢條件
如下:
匿名內部類使用。如果不是自己再封裝,需要指定泛型對象。

Specification<T> sp = new Specification<T>() {
			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				try {
					Path<Object> createTimePath = root.get("createTime");
//					query.orderBy(cb.desc(createTimePath));
				} catch (Exception e) {
					System.out.println("實體不存在createTime屬性");
				}
				if (StringUtils.isNotBlank(sortField)) {
					query.orderBy(cb.asc(root.get(sortField)));
					if (StringUtils.isNotBlank(order)) {
						if (order.equals("desc")) {
							query.orderBy(cb.desc(root.get(sortField)));
						}
					}
				}
				Predicate pred = fsp.toPredicate(root, query, cb);
				try {
					//獲取屬性
					Path<String> namePath = root.get("name");
					if (Util.isNotEmpty(name)) {
						//構造查詢條件可以cb.equal,cb.like等
						pred = cb.and(pred, cb.like(namePath, "%"+name+"%"));//and與形式拼接多個查詢條件
					}
				} catch (Exception e) {
					System.out.println("實體不存在name屬性");
				}
				return pred;
			}
		};

分頁參數
pageable

//默認當前頁
		if(Util.isEmpty(pageNum) || pageNum == 0){
			pageNum = 1;
		}
		//默認每頁條數
		if(Util.isEmpty(pageSize)){
			pageSize = 10;
		}
PageRequest pageable = new PageRequest(pageNum-1, pageSize,sort)
一對多關係

一方

//1、聲明關係 對方字節碼對象
//@OneToMany(targetEntity = People.class)
//放棄外鍵  對象導航查詢加載方式fetch 中EAGER 立即加載,LAZY延遲加載
@OneToMany(mappedBy="department",cascade=Cascade.ALL,fetch=FetchType.eager)
//2、配置外鍵(中間表)name外鍵名,referenceColumName主表主鍵
//@JoinColumn(name ="department_id",referenceColumName="id")
private Set<People> peoples = new HashSet<>();

多方

//1、聲明關係 對方字節碼對象
@ManyToOne(targetEntity = Department.class)
//2、配置外鍵(中間表)name外鍵名,referenceColumName主表主鍵
@JoinColumn(name ="id",referenceColumName="department_id")
private Department department;

都在多的一方維護外鍵

一的一方維護的話多一條update執行效果,先兩條insert,在一條update更新外鍵

級聯

刪除主表數據,會把外鍵字段設置爲null,然後刪除主表數據,如果配置了放棄維護關聯關係的權利,則不能上傳,如果還想刪除,使用級聯刪除引用,如果沒有從表數據,可以刪除。
操作:
1、需要區分操作主體
2、需要在操作主體的實體類上。添加級聯屬性
3、cascade 配置級聯

@OneToMany(mappedBy="department",cascade="CascadeType.ALL")

添加

Department department = new Department();
department.setName("2121");
People p = new People();
p.setName("5565");
department.getPoples.add(p);
departmentDao.save(department);

刪除就直接刪除一方就可以了

多對多關係

多方

//1、聲明關係 對方字節碼對象
@ManyToMany(targetEntity = Department.class)
//2、配置外鍵(中間表)name外鍵名,referenceColumName主表主鍵
@JoinTable(name ="department_role)",
//當前對象在中間表中的外鍵
joinColumns={@joinColumn((name ="id",referenceColumName="department_id")})
// 對方對象在中間表的外鍵
inverseColumns={@joinColumn((name ="id",referenceColumName="role_id")})
private Set<Department> departments = newHashSet<>();

另一個多方

//1、聲明關係 對方字節碼對象
@ManyToMany(mappedBy = "role")

private Set<Role> roles= newHashSet<>();

被動的一方放棄維護權

對象導航查詢

就是通過配置了多表映射,通過get對象得到關係對象信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章