spring boot(四)資料訪問模組
前言
做Web應用需要內容,而內容通常儲存於各種型別的資料庫,服務端在接收到訪問請求之後需要訪問資料庫獲取並處理成展現給使用者使用的資料形式。這篇部落格打算總結一下spring boot中的資料訪問模組,通過幾個簡單的例項完成helloworld級別的例項
JdbcTemplate資料訪問
spring中的JdbcTemplate是自動配置的,我們在使用的時候只需要注入就可以了,可以說非常easy了。直接上例項吧。
這裡為了簡單,例項只貼出service和其實現類,後期會將相關程式碼上傳到GitHub。
UserService
package com.learn.springBootDataAccess.service;
/**
*
* @author liman
* @createtime 2018年8月23日
* @contract 15528212893
* @comment:
* 使用者服務介面
*/
public interface UserService {
/**
* 新增一個使用者
* @param name
* @param age
*/
void create(String name, Integer age);
/**
* 根據name刪除一個使用者高
* @param name
*/
void deleteByName(String name);
/**
* 獲取使用者總量
*/
Integer getAllUsersSize();
/**
* 刪除所有使用者
*/
void deleteAllUsers();
}
userServiceImpl
package com.learn.springBootDataAccess.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
*
* @author liman
* @createtime 2018年8月23日
* @contract 15528212893
* @comment:
* userService的是實現類
*/
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void create(String name, Integer age) {
jdbcTemplate.update(
"insert into user(name,age) values(?,?)",name,age);
}
@Override
public void deleteByName(String name) {
jdbcTemplate.update("delete from user where name=?",name);
}
@Override
public Integer getAllUsersSize() {
return jdbcTemplate.queryForObject("select count(1) from USER", Integer.class);
}
@Override
public void deleteAllUsers() {
jdbcTemplate.update("delete from USER");
}
}
相關測試程式碼略去(非常easy,就不貼出來了)
總的來說,上述例項只是一個簡介,只是引入了spring 中jdbcTemplate自身的一個使用方式。通常實際開發中很少用到JdbcTemplate。多會採用更為成熟的資料層訪問框架。
JPA資料訪問
JPA在我個人理解,其就算是一個資料訪問層規範,Hibernate算是JPA的一種實現。
為了解決抽象各個Java實體基本的“增刪改查”操作,我們通常會以泛型的方式封裝一個模板Dao來進行抽象簡化,但是這樣依然不是很方便,我們需要針對每個實體編寫一個繼承自泛型模板Dao的介面,再編寫該介面的實現。雖然一些基礎的資料訪問已經可以得到很好的複用,但是在程式碼結構上針對每個實體都會有一堆Dao的介面和實現。
由於模板Dao的實現,使得這些具體實體的Dao層已經變的非常“薄”,有一些具體實體的Dao實現可能完全就是對模板Dao的簡單代理,並且往往這樣的實現類可能會出現在很多實體上。Spring-data-jpa的出現正可以讓這樣一個已經很“薄”的資料訪問層變成只是一層介面的編寫方式。
還是以User的資訊訪問為例:
User實體類
package com.learn.springBootDataAccess.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.springframework.lang.Nullable;
/**
*
* @author liman
* @createtime 2018年8月23日
* @contract 15528212893
* @comment: UserInfo實體
*/
@Entity
public class UserInfo {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfo [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
很薄的dao層(原諒我依舊用老的概念來理解)
package com.learn.springBootDataAccess.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.learn.springBootDataAccess.domain.UserInfo;
public interface UserRepository extends JpaRepository<UserInfo, Long> {
/**
* 這個是自動實現的,jpa會按方法名去解析sql語句
* @param name
* @return
*/
UserInfo findByName(String name);
/**
*
* @param name
* @param age
* @return
*/
UserInfo findByNameAndAge(String name,Integer age);
@Query("from UserInfo u where u.name=:name")
UserInfo findUserSelf(@Param("name") String name);
/**
* 儲存操作
*/
UserInfo save(UserInfo userInfo);
}
訪問層中不需要編寫任何的是實現程式碼,這就是Spring-data-jpa的一大特性:通過解析方法名建立查詢,該介面繼承自JpaRepository
,通過檢視JpaRepository
介面的API文件,可以看到該介面本身已經實現了建立(save)、更新(save)、刪除(delete)、查詢(findAll、findOne)等基本操作的函式,因此對於這些基礎操作的資料訪問就不需要開發者再自己定義。
在我們實際開發中,JpaRepository
介面定義的介面往往還不夠或者效能不夠優化,我們需要進一步實現更復雜一些的查詢或操作。由於本文重點在spring boot中整合spring-data-jpa,後面針對spring-data-jpa會進行深入的學習。
之後只需要在service層中輸入UserRepository就可以了,下面直接給出測試程式碼
package com.learn.springBootDataAccess;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.learn.springBootDataAccess.domain.UserInfo;
import com.learn.springBootDataAccess.repository.UserRepository;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
public void findByNameTest() {
UserInfo user = userRepository.findByName("liman_18");
System.out.println(user);
}
@Test
public void findByNameAndAgeTest() {
UserInfo user = userRepository.findByNameAndAge("liman_19", 19);
System.out.println(user);
}
@Test
public void addUserInfoTest() {
UserInfo userInfo = new UserInfo();
userInfo.setAge(19);
userInfo.setName("liman_19");
userRepository.save(userInfo);
}
@Test
public void findUserSelf() {
String userName = "liman_19";
UserInfo userInfo = userRepository.findUserSelf(userName);
System.out.println(userInfo.toString());
}
}
相關配置:
需要引入jpa的maven依賴
<dependency
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
application.properties中加入相關配置用於資料訪問
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.hbm2ddl.auto
是hibernate的配置屬性,其主要作用是:自動建立、更新、驗證資料庫表結構。該引數的幾種配置如下:
create
:每次載入hibernate時都會刪除上一次的生成的表,然後根據你的model類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致資料庫表資料丟失的一個重要原因。create-drop
:每次載入hibernate時根據model類生成表,但是sessionFactory一關閉,表就自動刪除。update
:最常用的屬性,第一次載入hibernate時根據model類會自動建立起表的結構(前提是先建立好資料庫),以後載入hibernate時根據model類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到伺服器後,表結構是不會被馬上建立起來的,是要等應用第一次執行起來後才會。validate
:每次載入hibernate時,驗證建立資料庫表結構,只會和資料庫中的表進行比較,不會建立新表,但是會插入新值。
整合MyBatis
之前第一份實習工作做的一個完成的專案就是用的MyBatis,但是還是基於XML配置去完成,整個dao層非常的臃腫,各種資料訪問檔案加起來有幾十個。這個例項雖然是helloworld,但是採用的是註解的方式實現相關功能。
資料訪問層依舊之後介面,沒有實現類。
對應的User例項:
這個時候的UserInfo例項不需要像hibernate一樣打上各種註解
package com.learn.springbootMybatis.domain;
public class UserInfoM {
private Long id;
private String name;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfoM [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
對應的資料訪問層
package com.learn.springbootMybatis.repo.Mapper;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.learn.springbootMybatis.domain.UserInfoM;
@Mapper
public interface UserMapper {
@Select("select * from user_info where name=#{name}")
UserInfoM findByName(@Param("name") String name);
@Insert("insert into user_info(name,age) values(#{name},#{age})")
int insert(@Param("name")String name,@Param("age") Integer age);
//使用Map資料結構進行資料插入
@Insert("insert into user_info(name,age) values(#{name,jdbcType=VARCHAR},#{age,jdbcType=INTEGER})")
int insertByMap(Map<String,Object> map);
@Insert("insert into user_info(name,age) values(#{name},#{age})")
int insertByUserInfoM(UserInfoM userInfo);
//修改和刪除
@Update("update user_info set age=#{age} where name = #{name}")
void upateAge(UserInfoM userInfo);
@Delete("delete from user_info where id = #{id}")
void delete(Long id);
@Results({
@Result(property = "name",column="name"),
@Result(property = "age",column="age")
})
@Select("select name,age from user_info")
List<UserInfoM> findAll();
}
測試實現的程式碼
package com.learn.springbootMybatis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.learn.springbootMybatis.domain.UserInfoM;
import com.learn.springbootMybatis.repo.Mapper.UserMapper;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void findByName() {
userMapper.insert("AAA", 20);
UserInfoM user = userMapper.findByName("AAA");
System.out.println(user);
}
@Test
public void insertByMap() {
Map<String,Object> map = new HashMap<String,Object>();
map.put("name", "liman");
map.put("age", 20);
userMapper.insertByMap(map);
}
@Test
public void insertByUserInfoM() {
UserInfoM userInfo = new UserInfoM();
userInfo.setAge(21);
userInfo.setName("huangrong");
userMapper.insertByUserInfoM(userInfo);
}
@Test
public void testUpdateUserInfoM() {
UserInfoM userInfo = userMapper.findByName("huangrong01");
System.out.println(userInfo);
userInfo.setAge(22);
userMapper.upateAge(userInfo);
}
@Test
public void testDelete() {
userMapper.delete(4L);
}
@Test
public void getAllListTest() {
List<UserInfoM> userList = userMapper.findAll();
for(UserInfoM userInfo:userList) {
System.out.println(userInfo);
}
}
}
MyBatis註解說明:
其實針對框架的使用,更多的是需要熟悉相關注解的含義。總體來說,就分為兩個方面,一個是引數的傳入,另一個就是返回引數的繫結。
引數的傳入
1、使用@Param
@Insert("insert into user_info(name,age) values(#{name},#{age})")
int insert(@Param("name")String name,@Param("age") Integer age);
在函式引數中標記@Param標籤,@Param中定義的name對應了SQL中的#{name},age同樣
2、使用Map結構傳入
@Insert("insert into user_info(name,age) values(#{name,jdbcType=VARCHAR},#{age,jdbcType=INTEGER})")
int insertByMap(Map<String,Object> map);
在insert的函式中,需要根據相關的屬性,設定變數的值。 變數名稱需要保證同名
@Test
public void insertByUserInfoM() {
UserInfoM userInfo = new UserInfoM();
userInfo.setAge(21);
userInfo.setName("huangrong");
userMapper.insertByUserInfoM(userInfo);
}
3、使用物件(最為常用)
@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
int insertByUser(User user);
SQL語句中的name和age,對應User中的name和age屬性。
@Test
public void testUpdateUserInfoM() {
UserInfoM userInfo = userMapper.findByName("huangrong01");
System.out.println(userInfo);
userInfo.setAge(22);
userMapper.upateAge(userInfo);
}
返回結果的繫結
只列出了單表的結果繫結(對於多表聯合查詢,暫時沒有列出)
@Results({
@Result(property = "name",column="name"),
@Result(property = "age",column="age")
})
@Select("select name,age from user_info")
List<UserInfoM> findAll();
@Result中的property屬性對應實體物件中的成員名,column對應SELECT出的欄位名。
相關文章
- Spring Boot入坑-5-資料訪問Spring Boot
- Spring Boot實現資料訪問計數器Spring Boot
- Spring Boot通過@ConfigurationProperties訪問靜態資料 - reflectoringSpring Boot
- Spring資料訪問Spring
- Spring Boot入門(五):使用JDBC訪問MySql資料庫Spring BootJDBCMySql資料庫
- spring boot(三)web模組Spring BootWeb
- Spring Boot入門(七):使用MyBatis訪問MySql資料庫(xml方式)Spring BootMyBatisMySql資料庫XML
- 使用Spring Boot實現模組化Spring Boot
- Spring Boot 2.x基礎教程:使用JdbcTemplate訪問MySQL資料庫Spring BootJDBCMySql資料庫
- Spring Boot入門(六):使用MyBatis訪問MySql資料庫(註解方式)Spring BootMyBatisMySql資料庫
- spring boot解決跨域訪問配置Spring Boot跨域
- Spring-boot模組化程式設計Springboot程式設計
- 使用 Spring Boot 構建可重用的模擬模組Spring Boot
- Spring Boot 揭祕與實戰(二) 資料儲存篇 – 資料訪問與多資料來源配置Spring Boot
- Spring Boot 模組工程(透過 Maven Archetype)建立Spring BootMaven
- Spring Boot + MyBatis 多模組專案搭建教程Spring BootMyBatis
- Spring boot學習(四)Spring boot整合DruidSpring BootUI
- Spring Boot系列(四):Spring Boot原始碼解析Spring Boot原始碼
- Spring Boot 2.0(四):使用 Docker 部署 Spring BootSpring BootDocker
- spring mvc 的jpa JpaRepository資料層訪問SpringMVC
- 如何訪問Docker容器中的Spring Boot日誌DockerSpring Boot
- Spring Boot中從自定義Logback訪問Spring Bean三種方法Spring BootBean
- Vue + Spring Boot 專案實戰(四):資料庫的引入VueSpring Boot資料庫
- Spring Boot之驗證模組應用總結2Spring Boot
- Spring Boot + Maven 多模組專案開發詳解Spring BootMaven
- 比nestjs更優雅的ioc:跨模組訪問資源JS
- Spring Boot 高效資料聚合之道Spring Boot
- ASP.NET Core模組化前後端分離快速開發框架介紹之3、資料訪問模組介紹ASP.NET後端框架
- Spring Boot系列(四) Spring Cloud 之 Config ClientSpring BootCloudclient
- 四:http模組HTTP
- Spring Boot - 多模組多環境配置,大廠必備技能Spring Boot
- Spring Boot(四):Thymeleaf 使用詳解Spring Boot
- Spring Boot (四)模板引擎Thymeleaf整合Spring Boot
- 內網模組放開外網訪問和 cdn內網
- Spring Boot 學習資料 (轉載)Spring Boot
- Spring Boot中使用PostgreSQL資料庫Spring BootSQL資料庫
- Spring Boot 多資料來源配置Spring Boot
- Spring Boot 配置多資料來源Spring Boot