數據庫開發是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提供了標準的接口用來操做數據庫; 增刪改查都有; 在一條鏈接中執行多條sql語句,jdbcTemplate提供了兩種方式,StatementCallback或者ConnectionCallback;api
代碼示例以下:
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()),"先插入後查詢失敗"); } }
JPA:java persistence API ,定義了對象關係映射以及實體對象持久化接口,不侷限於EJB,能夠脫離容器獨立運行,開發,測試,依賴Hibernate的支持; JPA所維護的核心是實體(EntityBean),經過一個持久化上下文來使用,持久化上下文包括三個部分;
組件 | 說明 |
---|---|
ORM關係描述 | 支持註解或者xml兩種形式描述,springboot中使用註解來描述 |
實體操做API | 經過規範能夠實現對實體的CRUD操做 |
JPQL查詢語言 | 約定了面向對象的查詢語言,能夠實現靈活的查詢 |
jpaRepository的功能體系以下:
能夠靈活的經過註解定義新的查詢方法;也能夠按照規則直接寫一個空方法和簽名
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
不屏蔽sql而且提供動態sql,接口式編程和簡易sql綁定pojo的半自動化框架; 目前java的持久層技術最爲主流的就是mybatis,它比jpa更易用和靈活; 適用於當前互聯網環境業務比較簡單,可是數據量大,高併發,性能問題敏感; 官方定義:支持定製化的sql,存儲過程,高級映射的優秀持久層框架。 幾乎避免了全部的jdbc代碼和手動設置參數以及獲取結果集。 mybatis經過xml或者註解把接口和POJO映射爲數據庫中的記錄。
高性能,靈活,方便
- 支持駝峯映射,sql跟pojo之間,減小了開發者的工做量;
- 沒有屏蔽sql,提供了靈活性,能夠最大限度的優化sql;
- 支持動態sql,適應需求變化
配置文件
由於註解的功能和可讀性限制,實際使用的較多的是xml來進行配置;
- 基礎配置文件;mybatis.config-location指定,裏面配置底層的mybatis
- 映射配置文件;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>
核心類: SqlSessionFactory 應用內部惟一 SqlSession 操做的核心類,通常在應用中作了擦除,即無感,轉而使用各類XMapper接口; Configuration: mybatis的核心配置
配置項目 | 說明 |
---|---|
settings | 設置mybatis的低層行爲,好比駝峯映射,執行器類型,緩存等 |
typeAliases | 類型別名,@Alias("aa") |
typeHandlers | 類型處理器,處理支持的類型,好比枚舉,LocalDate等 |
plugins | 插件,攔截器,mybatis最強大也是最危險的組件,經過代理和責任鏈模式完成,能夠修改底層的實現功能,見代碼 |
mappers | 映射器,核心組件,定義了sql和pojo的映射關係,可使用生成器生成 |
採用@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代碼;
- 掌握了常見的數據鏈接池有哪些?並簡單應用了DBCP2;
- spring-jdbc操做數據庫的完整過程;
- spring-jpa操做數據庫的完整過程;
- spring-mybatis操做數據庫的完整過程; 實際工做中能夠靈活選擇,不過通常一個團隊中只選擇一個架子,大部分是mybatis; 原創不易,轉載請註明出處。