springBoot 集成Mysql數據庫
前一段時間,我們大體介紹過SpringBoot,想必大家還有依稀的印象。我們先來回顧一下:SpringBoot是目前java世界最流行的一個企業級解決方案框架。它深度綁定了依賴注入和面向切片兩種編程思想。並且通過自動化的方式減少了編程人員在開發過程中大量的繁瑣的配置和通用的配置型的編碼,讓編程人員可以更加聚焦於業務,解決實際的問題。
我們的日常工作有機會主要是圍繞數據庫進行編程和設計,那么數據庫的增刪改查對於我們來說可以說是最重要最核心最需要掌握的能力。
本次,我們假設大家已經按照上次培訓的內容,下載了對應的spring框架,開發編譯器,maven等必備工具。在此基礎上,我們來聊聊springBoot集成Mysql數據庫。希望通過學習后,大家能夠發揮聰明材質,將Mysql庫更換成oracle庫甚至是sqlserver庫。
mysql庫的安裝,網絡上有很多其他教程,在此略過不談,我們假設大家的mysql庫已經安裝完畢。直接開始mysql庫的集成工作。
springBoot鏈接數據庫,有三種方式:
- 采用JDBC直接鏈接
- 采用JdbcTemplate鏈接
- 采用SpringDataJPA鏈接
- 通過其他框架鏈接
JDBC直接鏈接繁瑣,易錯。我們直接略過,不做考慮。通過其他框架如MyBatis等,種類繁多,我們后續再講。本次我們重點講解JdbcTemplate和SpringDataJPA。特別是SpringDataJPA。
JdbcTemplate在JDBC的基礎上做了大量的封裝,SpringDataJPA是基於JPA(java持久化規范,本質上是ORM)的規范的一層封裝,JPA的具體的實現有Hibernate,OpenJPA等。JdbcTemplate和SpringDataJPA的最大區別是JdbcTemplate主要操作sql數據庫,SpringDataJPA主要操作對象。
我們首先了解采用JdbcTemplate鏈接mysql
首先第一步,修改maven的pom文件,將mysql和jdbc依賴添加進去。
//第一個dependency,是添加的mysql鏈接java的驅動程序
//第二個dependency,是支持通過JDBC鏈接數據庫。和C#的ADO一樣,都是基於ODBC鏈接的。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
第二步,在配置文件application.properties中添加mysql鏈接串
###mysql 連接信息,test是數據庫名
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
###用戶名
spring.datasource.username=root
###密碼
spring.datasource.password=sa
###驅動
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
第三步,設計數據庫表
CREATE TABLE `ay_user` (
`id` varchar(32) NOT NULL,
`name` varchar(10) DEFAULT NULL COMMENT '用戶名',
`password` varchar(32) DEFAULT NULL COMMENT '密碼'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
第四步,建立對應的數據庫實體
public class AyUser {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private String id;
private String name;
private String password;
}
第五步利用springboot的jdbc類讀取。此處采用一個測試用例展現
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void mySqlTest(){
String sql = "select id,name,password from ay_user ";
//query(),查詢方法,傳入sql語句和RowMapper對象,返回對象List。
//RowMapper對象,將查詢出來的每一行數據封裝成用戶定義的類
List<AyUser> userList = (List<AyUser>) jdbcTemplate.query(sql, new RowMapper<AyUser>() {
@Override
public AyUser mapRow(ResultSet re, int rowNum) throws SQLException {
AyUser user = new AyUser();
user.setId(re.getString("id"));
user.setName(re.getString("name"));
user.setPassword(re.getString("password"));
return user;
}
});
System.out.println("查詢成功:");
for (AyUser user:userList){
System.out.println("[id]:"+user.getId()+";[name]:"+user.getName());
}
}
此處有部分細節需要進一步闡釋。
@Resource
private JdbcTemplate jdbcTemplate;
JdbcTemplate是一個通過JDBC鏈接數據庫的工具類,maven的pom文件中引入的
spring-boot-starter-data-jdbc中包含了spring-jdbc的包,我們主要通過它
來完成增刪改查
@Resource代表自動注入,通過這個注解,項目啟動后,SpringBoot會幫助我們實例化一個
JdbcTemplate對象,省去初始化工作
對於各種注解,可以查看一個腦圖,這個腦圖是基於自己的理解自行整理的,可能有錯誤或不全面,后面可以可以共同優化。

那么采用SpringDataJPA如何操作mysql數據庫呢?
具體操作之前,我們簡單了解一下SpringDataJPA。

SpringDataJPA最頂層的接口是Repository,它是一個空的,只定義了泛型和ID關鍵字(可以查看Repository源碼),CrudRepository則提供了基本的增刪改查接口,PagingAndSortingRepository提供了基本的分頁和排序接口,JpaRepository繼承了上述接口,是我們常用的底層的接口。
具體如何使用呢?
第一步,修改maven的pom文件,將jpa依賴添加進去。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
第二步,創建一個接口繼承JpaRepository接口(后期可以添加一些自定義的東西)
public interface AyUserRepository extends JpaRepository<AyUser,String> {
//自定義內容
List<AyUser> findByName(String name);
List<AyUser> findByNameLike(String name);
List<AyUser> findByIdIn(Collection<String> ids);
}
SpringDataJPA約定了一系列規范,JPA會根據代碼翻譯成相關的sql。如findBy,Like,In等關鍵字。
可從官網https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories的5.3.2的table3中查看全部寫法。
不完整截圖如下:

第三步,修改AyUser類,添加@Entity, @Id注解。
@Entity//每個持久化POJO類都是一個實體Bean,通過此注解申明
@Table(name="ay_user")//對象映射到數據庫的表,如果沒有,Spring會根據class的名字進行尋找
public class AyUser {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Id//表示表的主鍵
private String id;
private String name;
private String password;
}
第四部,模擬一個簡單的JPA實現
public interface AyUserService {
AyUser findById(String id);
List<AyUser> findAll();
AyUser save(AyUser ayUser);
void delete(String id);
//Pageable是一個分頁接口,Page是一個分頁查詢結果借口
Page<AyUser> findAll(Pageable pageable);
List<AyUser> findByName(String name);
List<AyUser> findByNameLike(String name);
List<AyUser> findByIdIn(Collection<String> ids);
}
@Service//服務類注解,和@Component起到類似的作用:自動掃描並注冊到Spring容器中
public class AyUserServiceImpl implements AyUserService {
@Resource//自動掃描AyUserRepository並注冊
private AyUserRepository ayUserRepository;
@Override
public AyUser findById(String id) {
return ayUserRepository.findById(id).get();
}
@Override
public List<AyUser> findAll() {
return ayUserRepository.findAll();
}
@Override
public AyUser save(AyUser ayUser) {
return ayUserRepository.save(ayUser);
}
@Override
public void delete(String id) {
ayUserRepository.deleteById(id);
}
//翻頁
@Override
public Page<AyUser> findAll(Pageable pageable) {
return ayUserRepository.findAll(pageable);
}
@Override
public List<AyUser> findByName(String name) {
return ayUserRepository.findByName(name);
}
@Override
public List<AyUser> findByNameLike(String name) {
return ayUserRepository.findByNameLike(name);
}
@Override
public List<AyUser> findByIdIn(Collection<String> ids) {
return ayUserRepository.findByIdIn(ids);
}
}
第五步,使用JPA進行增刪改查
@Resource
private AyUserService ayUserService;
@Test
public void testRepository(){
List<AyUser> userList = ayUserService.findAll();
System.out.println("findAll():"+userList.size());
List<AyUser> userList2 = ayUserService.findByName("文鵬");
System.out.println("findByName():"+userList2.size());
Assert.isTrue(userList2.get(0).getName().equals(("文鵬")));
List<AyUser> userList3 = ayUserService.findByNameLike("文%");
System.out.println("findByNameLike():"+userList3.size());
Assert.isTrue(userList3.get(0).getName().equals(("文鵬")));
List<String> ids = new ArrayList<String>();
ids.add("1");
ids.add("2");
List<AyUser> userList4 = ayUserService.findByIdIn(ids);
System.out.println("findByIdIn:"+userList4.size());
PageRequest pageRequest = PageRequest.of(0,10);
Page<AyUser> userList5 = ayUserService.findAll(pageRequest);
System.out.println("page findAll:"+userList5.getTotalPages()+"/"+userList5.getSize());
List<AyUser> userList6 = ayUserService.findByNameLike("%國%");
System.out.println("findByNameLike():"+userList6.size());
Assert.isTrue(userList6.get(0).getName().equals(("文國平")));
AyUser ayUser = new AyUser();
ayUser.setId("4");
ayUser.setName("李國正");
ayUser.setPassword("123");
ayUserService.save(ayUser);
List<AyUser> userList7 = ayUserService.findByNameLike("%國%");
System.out.println("findByNameLike():"+userList7.size());
Assert.isTrue(userList7.get(0).getName().equals(("文國平")));
ayUserService.delete("4");
List<AyUser> userList8 = ayUserService.findByNameLike("%國%");
System.out.println("findByNameLike():"+userList8.size());
Assert.isTrue(userList8.get(0).getName().equals(("文國平")));
}
事務是我們數據庫操作的重要組成部分,有很多業務場景需要事務的原子性,一致性,隔離性和持久性。
SpringBoot同時支持編程式事務管理和聲明式事務管理。編程式需要每個方法中額外增加提交和回滾動作,Spring推薦采用聲明式事務管理,並通過內置的Spring AOP切片框架支持。
那么通過SpringDataJPA如何實現事務?
SpringBoot默認開啟了JPA,JDBC,MyBatis的事務,無需我們做任何多余的配置。我們只需要對要起開事務的類或方法添加@Transactional注解即可。
@Transactional
@Service
public class AyUserServiceImpl implements AyUserService {
@Transactional
@Override
public void delete(String id) {
ayUserRepository.deleteById(id);
String e = null;
e.split("/");
}
}
@Transactional注解可以通過參數propagation定義事務的傳播級別,也可以通過參數isolation隔離級別。
@Transactional(propagation=Propagation.REQUIRED) //控制事務傳播。默認是Propagation.REQUIRED
@Transactional(isolation=Isolation.DEFAULT) //控制事務隔離級別。默認跟數據庫的默認隔離級別相同
@Transactional(readOnly=false) //控制事務可讀寫還是只可讀。默認可讀寫
@Transactional(timeout=30) //控制事務的超時時間,單位秒。默認跟數據庫的事務控制系統相同,又說是30秒
@Transactional(rollbackFor=RuntimeException.class) //控制事務遇到哪些異常才會回滾。默認是RuntimeException
@Transactional(rollbackForClassName=RuntimeException) //同上
@Transactional(noRollbackFor=NullPointerException.class) //控制事務遇到哪些異常不會回滾。默認遇到非RuntimeException不會回滾
@Transactional(noRollbackForClassName=NullPointerException)//同上
具體可參考文章: