0107 spring操做數據庫的3個架子

背景

數據庫開發是java的核心內容之一,基礎就是jdbc了; 然而直接使用jdbc,須要寫大量的try-catch-finally模板代碼; 管理系統使用hibernate做爲orm框架比較方便,遵循jpa規範; 互聯網時代使用Mybatis,由於靈活,方便進行sql優化; 此外spring也提供了jdbcTemplate的訪問數據庫的模式,不過沒有被大量的企業使用; 使用這些ORM框架以前,必須先配置好數據源;java

數據源

數據鏈接池,能夠複用鏈接mysql

常見數據庫 |數據庫|說明| |-|-| |h2|內存數據庫| |derby|內存數據庫| |hqldb|內存數據庫| |mysql|商用數據庫,開源免費| |oracle|商用數據庫,oracle| |mssql|即sql server 微軟提供|git

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

<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數據源:spring

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 = 配置數據鏈接池(org.apache.commons.dbp2.BasicDataSource)

默認使用的是hikaricp;sql

代碼以下:數據庫

@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());
	}
}

常見數據鏈接池apache

數據源 說明
tomcat tomcat內置,springboot自帶了
dbcp2 外部經典數據源
druid 阿里開源的容易監控容易擴展的數據源
hikricp 日本開源的一個超快的數據源

驗證配置的數據源:編程

JdbcTemplate

jdbcTemplate提供了標準的接口用來操做數據庫; 增刪改查都有; 在一條鏈接中執行多條sql語句,jdbcTemplate提供了兩種方式,StatementCallback或者ConnectionCallback;api

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
 * 建立時間: 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 ,定義了對象關係映射以及實體對象持久化接口,不侷限於EJB,能夠脫離容器獨立運行,開發,測試,依賴Hibernate的支持; JPA所維護的核心是實體(EntityBean),經過一個持久化上下文來使用,持久化上下文包括三個部分;

組件 說明
ORM關係描述 支持註解或者xml兩種形式描述,springboot中使用註解來描述
實體操做API 經過規範能夠實現對實體的CRUD操做
JPQL查詢語言 約定了面向對象的查詢語言,能夠實現靈活的查詢

jpaRepository的功能體系以下:

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

能夠靈活的經過註解定義新的查詢方法;也能夠按照規則直接寫一個空方法和簽名

依賴

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

JPA運行代碼點我!

Mybatis

不屏蔽sql而且提供動態sql,接口式編程和簡易sql綁定pojo的半自動化框架; 目前java的持久層技術最爲主流的就是mybatis,它比jpa更易用和靈活; 適用於當前互聯網環境業務比較簡單,可是數據量大,高併發,性能問題敏感; 官方定義:支持定製化的sql,存儲過程,高級映射的優秀持久層框架。 幾乎避免了全部的jdbc代碼和手動設置參數以及獲取結果集。 mybatis經過xml或者註解把接口和POJO映射爲數據庫中的記錄。

高性能,靈活,方便

  1. 支持駝峯映射,sql跟pojo之間,減小了開發者的工做量;
  2. 沒有屏蔽sql,提供了靈活性,能夠最大限度的優化sql;
  3. 支持動態sql,適應需求變化

配置文件

由於註解的功能和可讀性限制,實際使用的較多的是xml來進行配置;

  1. 基礎配置文件;mybatis.config-location指定,裏面配置底層的mybatis
  2. 映射配置文件;mybatis.mapper-locations=classpath:mapper/*.xml

依賴

社區最新版本

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

mybatis的配置

核心類: SqlSessionFactory 應用內部惟一 SqlSession 操做的核心類,通常在應用中作了擦除,即無感,轉而使用各類XMapper接口; Configuration: mybatis的核心配置

配置項目 說明
settings 設置mybatis的低層行爲,好比駝峯映射,執行器類型,緩存等
typeAliases 類型別名,@Alias("aa")
typeHandlers 類型處理器,處理支持的類型,好比枚舉,LocalDate等
plugins 插件,攔截器,mybatis最強大也是最危險的組件,經過代理和責任鏈模式完成,能夠修改底層的實現功能,見代碼
mappers 映射器,核心組件,定義了sql和pojo的映射關係,可使用生成器生成

整合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
 * 建立時間: 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
 * 建立時間: 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運行代碼點我!

小結

  1. 掌握了常見的數據鏈接池有哪些?並簡單應用了DBCP2;
  2. spring-jdbc操做數據庫的完整過程;
  3. spring-jpa操做數據庫的完整過程;
  4. spring-mybatis操做數據庫的完整過程; 實際工做中能夠靈活選擇,不過通常一個團隊中只選擇一個架子,大部分是mybatis; 原創不易,轉載請註明出處。
相關文章
相關標籤/搜索