springboot學習5——Datasource

一、配置數據源

1.引入了JPA的依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Spring Boot使用Hibernate實現JPA,所以我們就可以在不使用任何配置數據庫的情況下運行Spring Boot工程了.

2.配置MySQL的依賴

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

3.配置數據源

spring.datasource.url=jdbc:mysql://localhost:3306/chapter5
spring.datasource.username=root
spring.datasource.password=123456
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#最大等待連接中的數量, 設 0 爲沒有限制
spring.datasource.tomcat.max-idle=10
#最大連接活動數
spring.datasource.tomcat.max-active=50
#最大等待毫秒數, 單位爲 ms, 超過時間會出錯誤信息
spring.datasource.tomcat.max-wait=10000
#數據庫連接池初始化連接數
spring.datasource.tomcat.initial-size=5

這樣我們就完成了Spring Boot的數據源配置,注意Spring Boot會儘可能地去判斷數據源是什麼類型的,然後根據其默認的情況去匹配驅動類。在它不能匹配的情況下,我們可以明確地配置它,這樣就不會使用默認的驅動類了。
接着我們可以根據需要配置數據源的屬性,因爲上面使用的是Tomcat自帶的數據庫連接池,所以可以看到很多配置的代碼中帶有tomcat字樣。

上面只是匹配Spring Boot綁定的Tomcat的數據源,有時候我們希望使用的是第三方數據源,例如,要使用DBCP數據源,只需要加入DBCP的數據源的Maven依賴。
在Maven中加入DBCP數據源依賴

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
</dependency>

配置DBCP2數據源

spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_chapter5
spring.datasource.username=root
spring.datasource.password=123456
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#指定數據庫連接池的類型
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
#最大等待連接中的數量,設 0 爲沒有限制
spring.datasource.dbcp2.max-idle=10
#最大連接活動數
spring.datasource.dbcp2.max-total=50
#最大等待毫秒數, 單位爲 ms, 超過時間會出錯誤信息
spring.datasource.dbcp2.max-wait-millis=10000
#數據庫連接池初始化連接數
spring.datasource.dbcp2.initial-size=5

在上述代碼中,我們首先通過spring.datasource.type屬性指定了數據庫連接池的類型,然後再使用spring.datasource.dbcp2.*去配置數據庫連接池的屬性,這樣Spring Boot就會根據這些屬性去配置對應的數據庫連接池,
從而知道使用的是DBCP數據源。爲了驗證這個結果,我們新建一個Bean,如代碼清單5-6所示。

監測數據庫連接池類型

@Component
// 實現Spring Bean生命週期接口ApplicationContextAware 
public class DataSourceShow implements ApplicationContextAware {

    ApplicationContext applicationContext = null;

     // Spring容器會自動調用這個方法,注入Spring IoC容器
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
        DataSource dataSource = applicationContext.getBean(DataSource.class);
        System.out.println("--------------------------------");
        System.out.println(dataSource.getClass().getName());
        System.out.println("--------------------------------");
    }
}

上述代碼中實現了接口ApplicationContextAware 的方法setApplicationContext(),依照Spring Bean 生命週期的規則,在其初始化的時候該方法就會被調用,從而獲取Spring IoC容器的上下文(applicationContext),
這時通過getBean方法就可以獲取數據庫連接池,然後打印出數據連接池的全限定名,這樣就可以知道它使用的是哪種數據庫連接池了。啓動Spring Boot程序,就可以發現類似下面的日誌出現:

......
--------------------------------
org.apache.commons.dbcp2.BasicDataSource
--------------------------------
......

顯然這裏是使用DBCP2的數據庫連接池提供服務的。我們也可以通過類似的方法配置第三方數據源。

二、JdbcTemplate

1.JdbcTemplate的映射關係是需要開發者自己實現RowMapper的接口的,完成數據庫數據到POJO(Plain Ordinary Java Object)對象的映射。對於Java 8及以上版本,可以使用Lambda表達式來比較優雅地實現RowMapper接口,如果JDK的版本比較低,只能聲明類或者使用匿名類了。

2.對於增刪查改,主要是傳遞參數,然後執行SQL後返回影響數據庫記錄數。執行多條SQL時,JdbcTemplate每調用一次便會生成一個數據庫連接,很浪費資源,可以使用StatementCallback或者ConnectionCallback接口實現一個連接裏面執行多條SQL。

三、JPA(Hibernate)

JPA(Java Persistence API,Java持久化API),定義了對象關係映射(ORM)以及實體對象持久化的標準接口。
JPA作爲POJO持久化的標準規範,可以脫離容器獨立運行、開發和測試,更加方便。然而這套方案並未被企業廣泛使用,相對地JPA更多地是依靠Hibernate的支持才得以使用。

在Spring Boot中JPA是依靠Hibernate得以實現的,Hibernate在3.2版本中已經對JPA實現了完全的支持,這裏我們就以Hibernate方案來討論JPA的應用。

JPA所維護的核心是實體(Entity Bean),它是通過一個持久化上下文(Persistence Context)來使用的。持久化上下文包含以下3個部分:

•對象關係映射(Object Relational Mapping,簡稱ORM,或O/RM,或O/R映射)描述,JPA支持註解或XML兩種形式的描述,在Spring Boot中主要通過註解實現;
•實體操作API,通過這節規範可以實現對實體對象的CRUD操作,來完成對象的持久化和查詢;
•查詢語言,約定了面向對象的查詢語言JPQL(Java Persistence Query Language),通過這層關係可以實現比較靈活的查詢。

開發JPA
在Maven中引入了spring-boot-starter-data-jpa,這樣便能夠使用JPA編程了。

1.建表SQL

create table t_user(
    id int(12) not null auto_increment,
    user_name varchar(60) not null,
    /**性別列,1-男,2-女**/
    sex int(3) not null default 1 check (sex in(1,2)),
    note varchar(256) null,
    primary key(id)
);

2.定義用戶POJO

// 標明是一個實體類
@Entity(name="user")
// 定義映射的表
@Table(name = "t_user")
public class User {
    // 標明主鍵
    @Id
    // 主鍵策略,遞增
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private Long id = null;

    // 定義屬性和表的映射關係
    @Column(name = "user_name")
    private String userName = null;

    private String note = null;

    // 定義轉換器
    @Convert(converter = SexConverter.class)
    private SexEnum sex = null;

    /**** setter and getter ****/
}

@Entity標明這是一個實體類
@Table配置的屬性name指出它映射數據庫的表,這樣實體就映射到了對應的表上,
@Id標註那個屬性爲表的主鍵,註解@GeneratedValue則是可以配置採用何種策略生成主鍵,這裏採用GenerationType.IDENTITY,這是一種依賴於數據庫遞增的策略;
@Column標註除id外的屬性,因爲屬性名稱(userName)和數據庫列名(user_name)不一致,而其他的屬性名稱和數據庫列名保持一致,這樣就能與數據庫的表的字段一一對應起來了。

爲此Spring提供了JpaRepository接口提供基本CRUD操作,它本身也繼承了其他的接口。

Spring 的JPA接口設計
JPA最頂級的接口是Repository,它沒有定義任何方法,
它的子接口CrudRepository,定義了最基本的增刪改的操作,功能性還不足夠強大,
PagingAndSortingRepository繼承了它並且提供了分頁和排序的功能,
最後JpaRepository擴展了PagingAndSortingRepository,而且擴展了QueryByExampleExecutor接口,

一般而言,我們只需要定義JPA接口擴展JpaRepository便可以獲得JPA提供的方法了,例如,針對用戶類(User)的JPA接口定義,如代碼清單5-15所示。

3.定義JPA接口

public interface JpaUserRepository 
    extends JpaRepository<User, Long> {
}

繼承JpaRepository,獲得JPA提供的方法。

4.控制器測試

@Controller
@RequestMapping("/jpa")
public class JpaController {
    // 注入JPA接口,這裏不需要使用實現類
    @Autowired
    private JpaUserRepository jpaUserRepository = null;

    @RequestMapping("/getUser")
    @ResponseBody
    public User getUser(Long id) {
        // 使用JPA接口查詢對象
        User user = jpaUserRepository.findById(id).get();
        return user;
    }
}

Spring提供了兩個註解用來掃描對應的JPA接口和實體類,它們是@EnableJpaRepositories和@EntityScan。顧名思義,
@EnableJpaRepositories:啓用JPA和制定掃描的包,生成對應的Bean,裝配在IoC容器中
@EntityScan:通過掃描裝載JPA的實體類

5.Spring Boot啓動文件:將接口掃描到Spring IoC容器中

// 定義Spring Boot掃描包路徑
@SpringBootApplication(scanBasePackages = {"com.springboot.chapter5"})
// 定義JPA接口掃描包路徑
@EnableJpaRepositories(basePackages = "com.springboot.chapter5.dao")
// 定義實體Bean掃描包路徑
@EntityScan(basePackages = "com.springboot.chapter5.pojo")
public class Chapter5Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Chapter5Application.class, args);
    }
}

實際上,即使沒有使用註解@EnableJpaRepositories和@EntityScan,只要依賴了spring-boot-starter-data-jpa,Spring Boot 2.x也會對項目進行掃描,這樣JPA的實體和接口都會被掃描,只是使用它們可以更進一步配置JPA的相關信息而已。

6.對JPA進行一定的配置:

配置JPA屬性
#使用MySQL數據庫方言
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
#打印數據庫SQL
spring.jpa.show-sql=true
#選擇Hibernate數據定義語言(DDL)策略爲update
spring.jpa.hibernate.ddl-auto=update

但是有時我們可能需要更加靈活的查詢,這時可以使用JPA查詢語言(JPQL),它與Hibernate提供的HQL是十分接近的。這裏使用註解@Query標識語句就可以了。

定義查詢語句:
@Query("from user where user_name like concat(’%’, ?1, ‘%’) "
+ “and note like concat(’’, ?2, ‘%’)”)
public List findUsers(String userName, String note);

其中from user中的user是定義的實體類名稱(@Entity註解的name屬性),所以才能這樣定義一條JPQL,提供給上層調用。

按照一定規則命名的方法也可以在不寫任何代碼的情況下完成邏輯:
JPA的命名查詢

/**
 * 按用戶名稱模糊查詢
 * @param userName 用戶名
 * @return 用戶列表
 */
List<User> findByUserNameLike(String userName);

/**
 * 根據主鍵查詢
 * @param id -- 主鍵
 * @return 用戶
 */
User getUserById(Long id);

/**
 * 按照用戶名稱或者備註進行模糊查詢
 * @param userName 用戶名
 * @param note 備註
 * @return 用戶列表
 */
List<User> findByUserNameLikeOrNoteLike(String userName, String note);

可以看到,這裏的命名是以動詞(get/find)開始的,而以by代表按照什麼內容進行查詢。
例如,getUserById方法就是通過主鍵(id)對用戶進行查詢的,這樣JPA就會根據方法命名生成SQL來查詢數據庫了;
findByUserNameLike方法的命名則多了一個like,它代表着採用模糊查詢,也就是使用like關鍵字進行查詢;
findByUserNameLikeOrNoteLike這樣的命名,則涉及兩個條件,一個是用戶名(userName),另一個是備註(note),它們都採用了like,因此會執行模糊查詢,而它們之間採用的連接詞爲Or(或者),所以SQL的生成也採用了Or。

其實JPA所實現的功能通過mybatis跟mybatis-plus也都可以實現

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