0107 spring操作數(shù)據(jù)庫的3個架子

背景

數(shù)據(jù)庫開發(fā)是java的核心內(nèi)容之一,基礎(chǔ)就是jdbc了蕴纳;
然而直接使用jdbc会油,需要寫大量的try-catch-finally模板代碼;
管理系統(tǒng)使用hibernate作為orm框架比較方便古毛,遵循jpa規(guī)范翻翩;
互聯(lián)網(wǎng)時代使用Mybatis,因為靈活稻薇,方便進行sql優(yōu)化嫂冻;
此外spring也提供了jdbcTemplate的訪問數(shù)據(jù)庫的模式,不過沒有被大量的企業(yè)使用颖低;
使用這些ORM框架之前絮吵,必須先配置好數(shù)據(jù)源;

數(shù)據(jù)源

數(shù)據(jù)連接池忱屑,可以復用連接

常見數(shù)據(jù)庫

數(shù)據(jù)庫 說明
h2 內(nèi)存數(shù)據(jù)庫
derby 內(nèi)存數(shù)據(jù)庫
hqldb 內(nèi)存數(shù)據(jù)庫
mysql 商用數(shù)據(jù)庫,開源免費
oracle 商用數(shù)據(jù)庫蹬敲,oracle
mssql 即sql server 微軟提供

引入依賴:(spring-jdbc,mysql驅(qū)動)

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

springboot配置jdbc數(shù)據(jù)源:

spring.datasource.url = jdbc:mysql:localhost:3306/xxx
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.type = 配置數(shù)據(jù)連接池(org.apache.commons.dbp2.BasicDataSource)

默認使用的是hikaricp;

代碼如下:

@SpringBootApplication
public class DemoDatasourceTomcatApplication {
    public static void main(String[] args) {
        final ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoDatasourceTomcatApplication.class, args);
        final DataSource dataSource = applicationContext.getBean(DataSource.class);
        System.out.println(dataSource.getClass().getName());
    }
}

常見數(shù)據(jù)連接池

數(shù)據(jù)源 說明
tomcat tomcat內(nèi)置莺戒,springboot自帶了
dbcp2 外部經(jīng)典數(shù)據(jù)源
druid 阿里開源的容易監(jiān)控容易擴展的數(shù)據(jù)源
hikricp 日本開源的一個超快的數(shù)據(jù)源

驗證配置的數(shù)據(jù)源:

JdbcTemplate

jdbcTemplate提供了標準的接口用來操作數(shù)據(jù)庫伴嗡;
增刪改查都有;
在一條連接中執(zhí)行多條sql語句从铲,jdbcTemplate提供了兩種方式瘪校,StatementCallback或者ConnectionCallback;

file

代碼示例如下:

package com.springbootpractice.demo.demo_datasource_tomcat.dao.jdbc.impl;

import com.springbootpractice.demo.demo_datasource_tomcat.dao.entity.UserLoginEntity;
import com.springbootpractice.demo.demo_datasource_tomcat.dao.entity.enums.SexEnum;
import com.springbootpractice.demo.demo_datasource_tomcat.dao.jdbc.IUserJdbcBiz;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * 說明:jdbc樣板代碼
 * @author carter
 * 創(chuàng)建時間: 2020年01月07日 2:36 下午
 **/
@Service
public class UserJdbcBiz implements IUserJdbcBiz {

    private final JdbcTemplate jdbcTemplate;

    public UserJdbcBiz(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }


    @Override
    public UserLoginEntity getUserLogin(Long id) {

        String sql = "SELECT id,user_name,password,sex,note FROM user_login WHERE id=? ";
        Object[] params = {id};
        return jdbcTemplate.queryForObject(sql, params, getUserLoginMapper());
    }


    @Override
    public List<UserLoginEntity> findUserLogin(String userName, String note) {

        String sql = "SELECT id,user_name,password,sex,note FROM user_login WHERE user_name=? and note=?";
        Object[] params = {userName, note};
        return Optional.ofNullable(jdbcTemplate.query(sql, params, getUserLoginMapper()))
                .orElse(Collections.emptyList());
    }

    @Override
    public long createUserLogin(UserLoginEntity entity) {
        String sql = "INSERT INTO user_login(user_name, password, sex, note) VALUES (?,?,?,?)";
        Object[] params = {entity.getUserName(), entity.getPassword(), entity.getSex().getCode(), entity.getNote()};
        return jdbcTemplate.update(sql, params);
    }

    @Override
    public long updateUserLogin(UserLoginEntity entity) {
        String sql = "UPDATE user_login SET user_name=? , password=? , sex=? , note=? WHERE id=? ";
        Object[] params = {entity.getUserName(), entity.getPassword(), entity.getSex().getCode(), entity.getNote(), entity.getId()};
        return jdbcTemplate.update(sql, params);
    }

    @Override
    public long deleteUserLogin(Long id) {
        String sql = "DELETE FROM user_login WHERE id=? ";
        Object[] params = {id};
        return jdbcTemplate.update(sql, params);
    }

    public static RowMapper<UserLoginEntity> getUserLoginMapper() {
        return (ResultSet rs, int rowNum) -> UserLoginEntity.builder()
                .id(rs.getLong("id"))
                .userName(rs.getString("user_name"))
                .password(rs.getString("password"))
                .sex(SexEnum.getByCode(rs.getInt("sex")))
                .note(rs.getString("note"))
                .build();

    }


}

package com.springbootpractice.demo.demo_datasource_tomcat;

import com.springbootpractice.demo.demo_datasource_tomcat.dao.entity.UserLoginEntity;
import com.springbootpractice.demo.demo_datasource_tomcat.dao.entity.enums.SexEnum;
import com.springbootpractice.demo.demo_datasource_tomcat.dao.jdbc.IUserJdbcBiz;
import com.springbootpractice.demo.demo_datasource_tomcat.dao.jdbc.impl.UserJdbcBiz;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.StatementCallback;
import org.springframework.util.Assert;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Objects;

@SpringBootTest
class DemoDatasourceTomcatApplicationTests {

    @Autowired
    private IUserJdbcBiz userJdbcBiz;

    @Test
    void crateUserLoginTest() {

        final long id = userJdbcBiz.createUserLogin(UserLoginEntity.builder()
                .userName("carter.li")
                .password("abc123")
                .sex(SexEnum.MALE)
                .note("第一個賬號")
                .build());

        final UserLoginEntity userLogin = userJdbcBiz.getUserLogin(id);

        Assert.isTrue(Objects.equals(id,userLogin.getId()),"插入失敗");

    }

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Test
    void twoOperationOneConnectionTest() {

        final UserLoginEntity result = jdbcTemplate.execute((StatementCallback<UserLoginEntity>) statement -> {

            //先插入

            final int i = statement.executeUpdate("INSERT INTO user_login(user_name, password, sex, note) VALUES ('gemini.he','abc123456',2,'我是美女!')");

            //然后查詢
            final ResultSet resultSet = statement.executeQuery("SELECT id,user_name,password,sex,note FROM user_login WHERE user_name='gemini.he'");

             UserLoginEntity userLoginEntity =null;
            while (resultSet.next()){
            userLoginEntity = UserJdbcBiz.getUserLoginMapper().mapRow(resultSet, resultSet.getRow());
            }

            return userLoginEntity;
        });

        Assert.isTrue(Objects.equals("gemini.he",result.getUserName()),"先插入后查詢失敗");

    }
}

dbcp2和spring-jdb代碼路徑點我阱扬!

JPA(Hibernate)

JPA:java persistence API ,定義了對象關(guān)系映射以及實體對象持久化接口泣懊,不局限于EJB,可以脫離容器獨立運行,開發(fā)麻惶,測試馍刮,依賴Hibernate的支持;
JPA所維護的核心是實體(EntityBean),通過一個持久化上下文來使用窃蹋,持久化上下文包括三個部分卡啰;

組件 說明
ORM關(guān)系描述 支持注解或者xml兩種形式描述,springboot中使用注解來描述
實體操作API 通過規(guī)范可以實現(xiàn)對實體的CRUD操作
JPQL查詢語言 約定了面向?qū)ο蟮牟樵冋Z言,可以實現(xiàn)靈活的查詢

jpaRepository的功能體系如下:

sequenceDiagram
JpaReporsitory->>QueryByExampleExecutor: 查詢功能警没?
JpaReporsitory-->>PageingAndSortingRepository: 分頁和排序功能
JpaReporsitory-->>CrudRepository: 增刪改查功能

可以靈活的通過注解定義新的查詢方法匈辱;也可以按照規(guī)則直接寫一個空方法和簽名

依賴

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

JPA運行代碼點我!

Mybatis

不屏蔽sql并且提供動態(tài)sql,接口式編程和簡易sql綁定pojo的半自動化框架杀迹;
目前java的持久層技術(shù)最為主流的就是mybatis亡脸,它比jpa更易用和靈活佛南;
適用于當前互聯(lián)網(wǎng)環(huán)境業(yè)務(wù)比較簡單梗掰,但是數(shù)據(jù)量大,高并發(fā)嗅回,性能問題敏感及穗;
官方定義:支持定制化的sql,存儲過程绵载,高級映射的優(yōu)秀持久層框架埂陆。
幾乎避免了所有的jdbc代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集。
mybatis通過xml或者注解把接口和POJO映射為數(shù)據(jù)庫中的記錄娃豹。

高性能焚虱,靈活,方便

  1. 支持駝峰映射懂版,sql跟pojo之間鹃栽,減少了開發(fā)者的工作量;
  2. 沒有屏蔽sql躯畴,提供了靈活性民鼓,可以最大限度的優(yōu)化sql;
  3. 支持動態(tài)sql,適應(yīng)需求變化

配置文件

因為注解的功能和可讀性限制蓬抄,實際使用的較多的是xml來進行配置丰嘉;

  1. 基礎(chǔ)配置文件;mybatis.config-location指定嚷缭,里面配置底層的mybatis
  2. 映射配置文件饮亏;mybatis.mapper-locations=classpath:mapper/*.xml

依賴

社區(qū)最新版本

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

mybatis的配置

核心類:
SqlSessionFactory 應(yīng)用內(nèi)部唯一
SqlSession 操作的核心類耍贾,一般在應(yīng)用中做了擦除,即無感路幸,轉(zhuǎn)而使用各種XMapper接口荐开;
Configuration: mybatis的核心配置

配置項目 說明
settings 設(shè)置mybatis的低層行為,比如駝峰映射劝赔,執(zhí)行器類型誓焦,緩存等
typeAliases 類型別名,@Alias("aa")
typeHandlers 類型處理器,處理支持的類型,比如枚舉移层,LocalDate等
plugins 插件仍翰,攔截器,mybatis最強大也是最危險的組件观话,通過代理和責任鏈模式完成予借,可以修改底層的實現(xiàn)功能,見代碼
mappers 映射器频蛔,核心組件灵迫,定義了sql和pojo的映射關(guān)系,可以使用生成器生成

整合springboot

采用@MapperScan注解

@MapperScan(basePackages = "com.springbootpractice.demo.mybatis.dao",
        annotationClass = Repository.class
)

屬性配置:


mybatis.mapper-locations= classpath:mapper/*.xml
mybatis.type-aliases-package= com.springbootpractice.demo.mybatis.dao.entity
mybatis.type-handlers-package= com.springbootpractice.demo.mybatis.dao.entity.handler
mybatis.config-location= classpath:mybatis.xml
mybatis.executor-type= reuse

實體代碼晦溪,mapper接口瀑粥,xml配置比較常見,這里給出作為一個例子:

domain實體

package com.springbootpractice.demo.mybatis.dao.entity;

import com.springbootpractice.demo.mybatis.dao.entity.enums.SexEnum;
import lombok.Data;
import org.apache.ibatis.type.Alias;

import java.io.Serializable;

/**
 * 說明:TODO
 * @author carter
 * 創(chuàng)建時間: 2020年01月07日 5:06 下午
 **/
@Data
@Alias("userLogin")
public class UserLoginEntity implements Serializable {

    private Long id;

    private String userName;

    private String password;

    private SexEnum sex;

    private String  note;

}

mapper接口

package com.springbootpractice.demo.mybatis.dao.mapper;

import com.springbootpractice.demo.mybatis.dao.entity.UserLoginEntity;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

/**
 * 說明:TODO
 * @author carter
 * 創(chuàng)建時間: 2020年01月07日 5:17 下午
 **/
@Repository
public interface UserLoginMapper {

    /**
     * 通過id查詢用戶信息
     * @param id id
     * @return 用戶信息
     */
    UserLoginEntity getById(@Param("id") Long id);

}

sql和domain的映射xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.springbootpractice.demo.mybatis.dao.mapper.UserLoginMapper">

    <select id="getById" parameterType="java.lang.Long" resultType="userLogin">
        SELECT * FROM user_login where id=#{id}
    </select>

</mapper>

底層的mybatis配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//MYBATIS.ORG//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.springbootpractice.demo.mybatis.dao.plugin.MyPlugin">
            <property name="a" value="a"/>
        </plugin>
    </plugins>
</configuration>

代碼生成工具很多三圆,可以下一個idea插件或引入maven插件來生成domain,mapper,xml代碼狞换;

Mybatis_demo運行代碼點我!

小結(jié)

  1. 掌握了常見的數(shù)據(jù)連接池有哪些舟肉?并簡單應(yīng)用了DBCP2;
  2. spring-jdbc操作數(shù)據(jù)庫的完整過程修噪;
  3. spring-jpa操作數(shù)據(jù)庫的完整過程;
  4. spring-mybatis操作數(shù)據(jù)庫的完整過程路媚;
    實際工作中可以靈活選擇黄琼,不過一般一個團隊中只選擇一個架子,大部分是mybatis;
    原創(chuàng)不易整慎,轉(zhuǎn)載請注明出處脏款。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市院领,隨后出現(xiàn)的幾起案子弛矛,更是在濱河造成了極大的恐慌,老刑警劉巖比然,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丈氓,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機万俗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門湾笛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人闰歪,你說我怎么就攤上這事嚎研。” “怎么了库倘?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵临扮,是天一觀的道長。 經(jīng)常有香客問我教翩,道長杆勇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任饱亿,我火速辦了婚禮蚜退,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘彪笼。我一直安慰自己钻注,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布配猫。 她就那樣靜靜地躺著幅恋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪章姓。 梳的紋絲不亂的頭發(fā)上佳遣,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音凡伊,去河邊找鬼零渐。 笑死,一個胖子當著我的面吹牛系忙,可吹牛的內(nèi)容都是我干的诵盼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼银还,長吁一口氣:“原來是場噩夢啊……” “哼风宁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蛹疯,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤戒财,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后捺弦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饮寞,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡孝扛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了幽崩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苦始。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖慌申,靈堂內(nèi)的尸體忽然破棺而出陌选,到底是詐尸還是另有隱情,我是刑警寧澤蹄溉,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布咨油,位于F島的核電站,受9級特大地震影響柒爵,放射性物質(zhì)發(fā)生泄漏臼勉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一餐弱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囱晴,春花似錦膏蚓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至枯芬,卻和暖如春论笔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背千所。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工狂魔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人淫痰。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓最楷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親待错。 傳聞我的和親對象是個殘疾皇子籽孙,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL火俄、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,523評論 0 4
  • 開發(fā)Web應(yīng)用犯建,數(shù)據(jù)的存儲和處理往往離不開數(shù)據(jù)庫和SQL語句。在使用Java開發(fā)的Web應(yīng)用中瓜客,自然也少不了連接數(shù)...
    灰色程序閱讀 1,469評論 0 25
  • 一德迹、概述 面試,難還是不難揭芍?取決于面試者的底蘊(氣場+技能)胳搞、心態(tài)和認知及溝通技巧。面試其實可以理解為一場聊天和談...
    編輯小猿閱讀 1,914評論 1 3
  • 任何時候都要無條件自信称杨,即使你做錯時肌毅。這是哈佛陽光心態(tài)的第一條。
    luckyapple666閱讀 147評論 0 1
  • 姓名:張景方 公司:上海日朗門窗有限公司 反省一組 【日精進打卡第223天】 【知~學習】 《六項精進》誦讀0遍共...
    威廉張豆豆爹閱讀 143評論 0 0