一、建立項目
依賴項選擇:
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>JPADemo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>JPADemo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
二、設置數據源 application.properties
#應用名稱
spring.application.name=springboot-demo
server.port=8888
server.servlet.context-path=/website
#編碼格式
server.tomcat.uri-encoding=utf-8
#數據庫相關配置
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://127.0.0.1:1433/springbootTestDB
spring.datasource.username=sa
spring.datasource.password=6617saSA
#指定連接池最大的空閑連接數量
spring.datasource.max-idle=10
#指定連接池等待連接返回的最大等待時間,毫秒單位
spring.datasource.max-wait=10000
#指定必須保持連接的最小值(For DBCP and Tomcat connection pools)
spring.datasource.min-idle=5
#指定啟動連接池時,初始建立的連接數量
spring.datasource.initial-size=5
#session生命周期
server.servlet.session.timeout=30m
三、創建User的實體類(省略了getter&setter方法)
package com.example.jpademo.Entity; import lombok.Data; import javax.persistence.*; /*使用JPA注解配置映射關系,告訴JPA這是一個實體類(和數據表映射的類)*/ @Data @Entity @Table(name = "t_user") //@Table來指定和哪個數據表對應;如果省略,默認表名就是該類名的小寫:user public class User { @Id //表示這個屬性是數據表中的主鍵 @GeneratedValue(strategy = GenerationType.IDENTITY) //還是一個自增的主鍵 private Long id; @Column(name = "firstName", length = 50) private String firstName; @Column(name = "lastName", length = 50) private String lastName; @Column //省略的情況,默認列名就是屬性名,均是小寫 private String Email; //String數據庫默認定義為varchar(255) protected User() {}; public User(String firstName,String lastName){ this.firstName=firstName; this.lastName=lastName; } }
使用JPA的一個好處就是,它能夠根據實體類自動幫我們創建對應的數據庫表,只需簡單配置幾步即可:
在application.properties文件中增加(jpa 也是spring下的一個屬性,所以它也是在spring這個層級下的):
#update:表的生成策略,第一次啟動根據實體建立表結構,之后啟動會根據實體的改變更新表結構,之前的數據都在。
spring.jpa.hibernate.ddl-auto=create
#在控制台輸出SQL
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
運行主程序,錯誤!!!
四、安裝Sql Server JDBC驅動
建立目錄jdbc , 將mssql-jdbc-6.4.0.jre8.jar拷貝到該目錄,加入庫中:
運行仍然錯誤!
錯誤原因:數據源的url定義錯誤
錯誤:spring.datasource.url=jdbc:sqlserver://127.0.0.1:1433/springbootTestDB
正確:spring.datasource.url=jdbc:sqlserver://127.0.0.1:1433;DatabaseName=springbootTestDB
修改后運行結果:
建立的數據庫:
說明:
JPA命名數據庫字段的規則:
@Column(name = "firstName", length = 50) private String firstName;
雖然用 @Column 命名了數據庫字段名稱,但是數據庫中仍然用 first_name 而不是 firstName , 原因:駝峰命名的字段改為用下划線隔開的的方式。
如果改為
@Column(name = "firstname", length = 50) 改為小寫,數據庫字段名稱就是 firstname
private String firstName;
默認Java對象的駝峰式命名對應數據庫的下划線命名
五、創建接口(持久層接口)
JPA中有許多封裝好的對數據庫進行操作的方法,不需要再寫sql語句,而是直接調用其中的方法,就可以完成對數據的操作。持久層接口需繼承JpaRepository類。
package com.example.jpademo.Dao; import com.example.jpademo.Entity.User; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User,Long> { }
六、修改入口類
package com.example.jpademo; import com.example.jpademo.Dao.UserRepository; import com.example.jpademo.Entity.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class JpaDemoApplication { private static final Logger log= LoggerFactory.getLogger(JpaDemoApplication.class); public static void main(String[] args) { SpringApplication.run(JpaDemoApplication.class, args); } @Bean public CommandLineRunner demo(UserRepository respository) { return (args) -> { respository.save(new User("張","少華")); respository.save(new User("李","三立")); respository.save(new User("王","大海")); respository.save(new User("王","大海")); respository.save(new User("王","大海")); log.info("-----------------------------------"); for(Object user: respository.findAll()) { log.info(user.toString()); } log.info("-----------------------------------"); respository.findById(1L).ifPresent( user-> { log.info("User found with findBtId(1L):"); log.info(user.toString()); } ); }; } }
運行結果:
七、程序擴展:創建UserCrudRepository
package com.example.jpademo.Dao; import com.example.jpademo.Entity.User; import org.springframework.data.repository.CrudRepository; import java.util.List; public interface UserCrudReposity extends CrudRepository<User,Long> { List<User> findByLastName(String lastName); //根據JPA命名規則,自動生成SQL }
八、修改入口類的代碼
package com.example.jpademo; import com.example.jpademo.Dao.UserCrudReposity; import com.example.jpademo.Dao.UserRepository; import com.example.jpademo.Entity.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class JpaDemoApplication { private static final Logger log= LoggerFactory.getLogger(JpaDemoApplication.class); public static void main(String[] args) { SpringApplication.run(JpaDemoApplication.class, args); } @Bean public CommandLineRunner demo(UserCrudReposity respository) { return (args) -> { respository.save(new User("張","少華")); respository.save(new User("李","三立")); respository.save(new User("王","大海")); respository.save(new User("王","大海")); respository.save(new User("王","大海")); log.info(""); log.info("-----------------------------------"); for(Object user: respository.findAll()) { log.info(user.toString()); } log.info(""); log.info("-----------------------------------"); respository.findById(1L).ifPresent( user-> { log.info("User found with findBtId(1L):"); log.info(user.toString()); } ); log.info(""); log.info("\n\n------------ 以大海的查詢結果 -----------------------"); for(Object user: respository.findByLastName("大海")) { log.info(user.toString()); } log.info("\n\n------------ 以大海的查詢結果 -----------------------"); respository.findByLastName("大海").forEach(user->{ // 默認的命名規則 log.info(user.toString()); }); }; } }
運行結果:
九、JPA訪問數據庫的命名規則(命名查詢)
public interface UserCrudReposity extends CrudRepository<User,Long> { List<User> findByLastName(String lastName); }
前面定義的接口中的方法:List<User> findByLastName(String lastName) 並沒有實現代碼,這里JPA采用了默認的命名規則,參見:
https://docs.spring.io/spring-data/jpa/docs/2.0.9.RELEASE/reference/html/#jpa.repositories 參見 5.3.2. 的Table 3
使用命名查詢來聲明實體查詢是一種有效的方法,並且適用於少量查詢。
十、使用 @Query
注釋創建自定義查詢
package com.example.jpademo.Dao; import com.example.jpademo.Entity.User; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import java.util.List; public interface UserCrudReposity extends CrudRepository<User,Long> { List<User> findByLastName(String lastName); @Query("select u from User u where u.lastName like %?1% or u.Email like %?2%") List<User> findByEmailAndFirstName(String lastname , String email); }
十一、定義控制器
package com.example.jpademo.Controller; import com.example.jpademo.Dao.UserCrudReposity; import com.example.jpademo.Entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Optional; @Controller @RequestMapping(path="/demo") public class UserController { //@Autowired是spring的自動裝配,可用於構造器、變量域、方法、注解類型上。當需要從bean工廠中獲取一個bean時, // Spring會自動為我們裝配該bean中標記為@Autowired的元素。 @Autowired private UserCrudReposity userCrudReposity; @GetMapping(path="/add") @ResponseBody //在瀏覽器中輸入 http://localhost:8888/website/demo/add?firstname=張&lastname=宇航, public String addNewUser(@RequestParam String firstname,@RequestParam String lastname) { User user=new User(firstname,lastname,""); userCrudReposity.save(user); return "saved"; } //http://localhost:8888/website/demo/finduser/大海 @GetMapping(path="/finduser/{lastname}") //1個占位符 @ResponseBody public String finduser(@PathVariable("lastname") String lastname) { List<User> userList= userCrudReposity.findByLastName(lastname); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } //http://localhost:8888/website/demo/finduser?lastname=大海&email=139 @GetMapping(path="/finduser") //用請求參數 @ResponseBody public String finduser1(@RequestParam String lastname,@RequestParam String email) { List<User> userList= userCrudReposity.findByEmailAndFirstName(lastname,email); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } //http://localhost:8888/website/demo/finduser/大海/139 @GetMapping(path="/finduser/{lastname}/{email}") //2個占位符 @ResponseBody public String finduser2(@PathVariable("lastname") String lastname, @PathVariable("email") String email) { List<User> userList= userCrudReposity.findByEmailAndFirstName(lastname,email); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } }
十二、擴展
數據庫訪問:
package com.example.jpademo.Dao; import com.example.jpademo.Entity.User; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; import java.util.List; public interface UserCrudReposity extends CrudRepository<User,Long> { List<User> findByLastName(String lastName); @Query("select u from User u where u.lastName like %?1% or u.Email like %?2%") List<User> findByEmailAndFirstName(String lastname , String email); @Query("select u from User u where u.firstName=?1 and u.lastName=?2") public List<User> queryUser(String fname,String lname); @Query("select u from User u where u.firstName=:fname and u.lastName=:lname") public List<User> queryUser1(@Param("fname") String firstname, @Param("lname") String lastname); @Transactional @Modifying(clearAutomatically = true) //@Modifying @Query("update User u set u.Email = ?1 where u.lastName=?2") int updateEmailBylastName(String email,String lastName); }
控制器:
package com.example.jpademo.Controller; import com.example.jpademo.Dao.UserCrudReposity; import com.example.jpademo.Entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Optional; @Controller @RequestMapping(path="/demo") public class UserController { //@Autowired是spring的自動裝配,可用於構造器、變量域、方法、注解類型上。當需要從bean工廠中獲取一個bean時,Spring會自動為我們裝配該bean中標記為@Autowired的元素。 //@Autowired-標記要通過 Spring 依賴注入自動裝配的構造函數,字段或 setter 方法。 @Autowired private UserCrudReposity userCrudReposity; @GetMapping(path="/add") @ResponseBody //在瀏覽器中輸入 http://localhost:8888/website/demo/add?firstname=張&lastname=宇航 public String addNewUser(@RequestParam String firstname,@RequestParam String lastname) { User user=new User(firstname,lastname,""); userCrudReposity.save(user); return "saved"; } //http://localhost:8888/website/demo/finduser/大海 @GetMapping(path="/finduser/{lastname}") //1個占位符 @ResponseBody public String finduser(@PathVariable("lastname") String lastname) { List<User> userList= userCrudReposity.findByLastName(lastname); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } //http://localhost:8888/website/demo/finduser?lastname=大海&email=139 @GetMapping(path="/finduser") //用請求參數 @ResponseBody public String finduser1(@RequestParam String lastname,@RequestParam String email) { List<User> userList= userCrudReposity.findByEmailAndFirstName(lastname,email); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } //http://localhost:8888/website/demo/finduser/大海/139 @GetMapping(path="/finduser/{lastname}/{email}") //2個占位符 @ResponseBody public String finduser2(@PathVariable("lastname") String lastname, @PathVariable(value = "email") String email) { List<User> userList= userCrudReposity.findByEmailAndFirstName(lastname,email); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } @GetMapping(path="/queryUser") @ResponseBody public String queryUser(@RequestParam String firstname,@RequestParam String lastname) { List<User> userList= userCrudReposity.queryUser(firstname,lastname); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } @GetMapping(path="/queryUser1") @ResponseBody public String queryUser1(@RequestParam String firstname,@RequestParam String lastname) { List<User> userList= userCrudReposity.queryUser1(firstname,lastname); String users=""; for(User user:userList) { users+=user.toString()+" "; } return users; } @GetMapping(path="/update") @ResponseBody public String update(@RequestParam String lastname,@RequestParam String email) { userCrudReposity.updateEmailBylastName(email,lastname); return "update"; } }