springboot-mybatis-oracle學習筆記

前言

最近公司的項目是基於 oracle 數據庫的,這裏記錄下 springboot+mybatis+oracle 的踩坑過程。java

開發前準備

環境參數

  • 開發工具:IDEA
  • 基礎工具:Maven+JDK8
  • 所用技術:SpringBoot+Mybatis+Oracle
  • 數據庫:MySQL5.7
  • SpringBoot 版本:2.2.6.RELEASE
  • Mybatis 版本: 2.1.2
  • Oracle: oracle-xe-11g

基於 Docker 搭建 Oracle

docker-compose-oracle.yml

version: '2'
services:
  oracle:
    image: sath89/oracle-xe-11g
    container_name: oracle
    ports:
      - 1521:1521
      - 8082:8080
    volumes:
      - ./oracle/data:/u01/app/oracle

鏈接參數

  • Connection Type: Basic
  • Host: localhost
  • Port: 1521
  • Service Name: xe
  • Username: system
  • Password: oracle

建立 表空間

Navicat 建立表空間mysql

腳本建立表空間web

-- 表空間 OA
-- 表空間物理文件位置 /u01/app/oracle/oradata/XE/OA
-- 大小20M
-- 每次20M自動增大
-- 最大100M
CREATE TABLESPACE "OA" DATAFILE '/u01/app/oracle/oradata/XE/OA' SIZE 20 M AUTOEXTEND ON NEXT 20 M MAXSIZE 100 M

建立 用戶 並綁定 角色

Navicat 建立用戶spring

Navicat 綁定角色sql

腳本建立用戶並綁定角色docker

CREATE USER "OA" IDENTIFIED BY "123456" DEFAULT TABLESPACE "OA" TEMPORARY TABLESPACE "TEMP";

GRANT "DBA" TO "root";

ALTER USER "root" DEFAULT ROLE "DBA"

設計 Entity

public class Account {

    // 主鍵
    private Integer id;
    // 用戶名(惟一)
    private String realName;
    // 工號(遞增)
    private Integer jobNumber;
    // 建立時間
    private Date createTime;

    public Account() {
    }

    public Account(String realName, Integer jobNumber) {
        this.realName = realName;
        this.jobNumber = jobNumber;
        this.createTime = new Date();
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public Integer getJobNumber() {
        return jobNumber;
    }

    public void setJobNumber(Integer jobNumber) {
        this.jobNumber = jobNumber;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", realName='" + realName + '\'' +
                ", jobNumber=" + jobNumber +
                ", createTime=" + createTime +
                '}';
    }
}

建立數據庫

-- ID 主鍵、自增
-- USER_NAME 惟一索引
-- JOB_NUMBER 遞增
CREATE TABLE "OA"."ACCOUNT" (
"ID" NUMBER(18, 0) NOT NULL ,
"REAL_NAME" VARCHAR2(128) NOT NULL ,
"JOB_NUMBER" NUMBER(18,0) DEFAULT 0 NOT NULL ,
"CREATE_TIME" TIMESTAMP(6) NULL ,
PRIMARY KEY ("ID")
);

-- 字段說明
COMMENT ON table ACCOUNT IS '帳戶表';
COMMENT ON COLUMN "OA"."ACCOUNT"."ID" IS '主鍵';
COMMENT ON COLUMN "OA"."ACCOUNT"."REAL_NAME" IS '用戶名';
COMMENT ON COLUMN "OA"."ACCOUNT"."JOB_NUMBER" IS '工號';
COMMENT ON COLUMN "OA"."ACCOUNT"."CREATE_TIME" IS '建立時間';

-- 建立惟一索引
CREATE UNIQUE INDEX INDEX_REAL_NAME on ACCOUNT(REAL_NAME);

-- 建立ID遞增序列
CREATE SEQUENCE ACCOUNT_ID_SEQ INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE NOCACHE;

-- 建立觸發器實現主鍵自增
CREATE OR REPLACE TRIGGER ACCOUNT_TRG BEFORE INSERT ON ACCOUNT FOR EACH ROW
BEGIN
    SELECT ACCOUNT_ID_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
END;

-- 查看序列
SELECT * FROM user_sequences;
-- 查看觸發器
SELECT * FROM user_triggers;

代碼實踐

配置文件

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.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.idea360</groupId>
    <artifactId>idc-oracle</artifactId>
    <version>0.0.1</version>
    <name>idc-oracle</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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>com.oracle.ojdbc</groupId>
            <artifactId>ojdbc8</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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.ymlapache

server:
  port: 9090
spring:
  profiles:
    active: local

mybatis:
  type-aliases-package: cn.idea360.oracle.model
  configuration:
    map-underscore-to-camel-case: true
    default-fetch-size: 100
    default-statement-timeout: 30
  mapper-locations: mapper/*.xml

logging:
  level:
    root: info

application-local.yml數組

spring:
  datasource:
    driver-class-name: oracle.jdbc.driver.OracleDriver
    url: jdbc:oracle:thin:@127.0.0.1:1521:XE
    username: oa
    password: 123456

mybatis-config.xmlspringboot

<?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>
    <typeAliases>
        <typeAlias alias="account" type="cn.idea360.oracle.model.Account"/>
    </typeAliases>
</configuration>

Java 代碼

mapper 包掃描配置

@MapperScan("cn.idea360.oracle.dao")
@SpringBootApplication
public class OracleApp {

    public static void main(String[] args) {
        SpringApplication.run(OracleApp.class, args);
    }

}

分頁

/**
 * Mapper進一步實現能夠基於攔截器實現
 * @param <T>
 */
@Data
public class Page<T> {

    /**
     * 查詢數據列表
     */
    private List<T> records = Collections.emptyList();
    /**
     * 總數
     */
    private long total = 0;
    /**
     * 每頁顯示條數,默認 10
     */
    private long size = 10;
    /**
     * 當前頁
     */
    private long current = 1;
    /**
     * KEY/VALUE 條件
     */
    private Map<Object, Object> condition;

    /**
     * oracle分頁: start
     */
    private Integer startIndex = 1;
    /**
     * oracle分頁: end
     */
    private Integer endIndex = 10;

    public Page() {
    }

    public Page(long current, long size) {
        this(current, size, 0);
    }

    public Page(long current, long size, long total) {
        if (current > 1) {
            this.current = current;
        }
        this.size = size;
        this.total = total;
    }

    /**
     * 計算當前分頁偏移量
     */
    public long offset() {
        return getCurrent() > 0 ? (getCurrent() - 1) * getSize() : 0;
    }

    /**
     * 當前分頁總頁數
     */
    public long getPages() {
        if (getSize() == 0) {
            return 0L;
        }
        long pages = getTotal() / getSize();
        if (getTotal() % getSize() != 0) {
            pages++;
        }
        return pages;
    }

    /**
     * oracle分頁開始
     * @return
     */
    public long getStartIndex() {
        return (getCurrent()-1)*size+1;
    }

    /**
     * oracle分頁結束
     * @return
     */
    public long getEndIndex() {
        return getCurrent()*size;
    }

}

mapper 定義

public interface AccountMapper {

    /**
     * 插入單條數據
     * @param account
     * @return 返回主鍵id
     */
    int insert(Account account);

    /**
     * 批量插入list
     * @param data
     */
    void insertBatch(@Param("coll") Collection<Account> data);

    /**
     * 更新數據
     * @param account
     * @return
     */
    int updateIgnoreNullById(@Param("et") Account account);

    /**
     * 刪除數據
     * @param id
     * @return
     */
    int removeById(@Param("id") Integer id);

    /**
     * 根據id查詢數據
     * @param id
     * @return
     */
    Account selectById(@Param("id") Integer id);

    /**
     * 根據其餘字段查詢數據
     * @param columnMap
     * @return
     */
    Account selectByMap(@Param("cm") Map<String, Object> columnMap);

    /**
     * 根據id數組批量查詢數據
     * @param idArray
     * @return
     */
    List<Account> selectByIds(@Param("coll") Integer[] idArray);

    /**
     * 根據分頁參數查詢數據
     * @param page
     * @return
     */
    List<Account> selectPage(@Param("page") Page page);

    /**
     * 查詢全部
     * @return
     */
    List<Account> listAll();

}

AccountMapper.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="cn.idea360.oracle.dao.AccountMapper">

    <!--resultType是直接表示返回類型的(對應着咱們的model對象中的實體),而resultMap則是對外部ResultMap的引用(提早定義了db和model之間的隱射key-value關係)-->
    <resultMap id="accountMap" type="account">
        <id column="id" property="id" />
        <result column="real_name" property="realName"/>
        <result column="job_number" property="jobNumber" />
        <result column="create_time" property="createTime" />
    </resultMap>

    <!--插入單條數據,自增主鍵經過序列和觸發器實現-->
    <insert id="insert"  parameterType="account" useGeneratedKeys="true">
        insert into account (real_name, job_number, create_time)
        values
            (#{realName}, #{jobNumber}, #{createTime})
        <selectKey keyProperty="id" resultType="java.lang.Integer" order="AFTER">
            select ACCOUNT_ID_SEQ.CURRVAL from dual
        </selectKey>
    </insert>

    <!--經過list批量插入數據-->
    <insert id="insertBatch" parameterType="java.util.List">
        insert into account (real_name, job_number, create_time)
        <foreach collection="coll" item="item"  index="index" separator="UNION ALL">
            select
            #{item.realName}, #{item.jobNumber}, #{item.createTime}
            from dual
        </foreach>
    </insert>

    <!--更新數據-->
    <update id="updateIgnoreNullById">
        update account
        <set>
            <if test="et.realName != null">
                real_name = #{et.realName},
            </if>
            <if test="et.jobNumber != null">
                job_number = #{et.jobNumber},
            </if>
        </set>
        where id = #{et.id}
    </update>

    <!--根據主鍵id移除數據-->
    <delete id="removeById">
        delete from account where id = #{id}
    </delete>

    <!--根據主鍵id查詢數據-->
    <select id="selectById" parameterType="integer" resultMap="accountMap">
        select * from account where id = #{id}
    </select>

    <!--根據其餘字段查詢數據-->
    <select id="selectByMap" resultMap="accountMap">
        select * from account
        <where>
            <if test="cm != null and cm.realName != null">
                and real_name = #{cm.realName}
            </if>
        </where>
    </select>

    <!--根據id數組查詢數據-->
    <select id="selectByIds" resultMap="accountMap">
        select * from account where id in
        <foreach collection="coll" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>

    <!--根據分頁參數查詢數據-->
    <select id="selectPage" resultMap="accountMap">
        SELECT
        T2.*
        FROM
        ( SELECT T1.*, ROWNUM RN FROM ( SELECT a.* FROM account a
        <where>
            <if test="page != null and page.condition != null and page.condition.keyword != null">
                AND a.real_name LIKE '%' ||  #{page.condition.keyword} || '%'
            </if>
        </where>
        ORDER BY id DESC
        ) T1 ) T2
        <where>
            <if test="page != null and page.startIndex != null">
                and RN <![CDATA[ >= ]]> #{page.startIndex}
            </if>
            <if test="page != null and page.endIndex != null">
                AND RN <![CDATA[ <= ]]> #{page.endIndex}
            </if>
        </where>
    </select>
    <select id="listAll" resultType="cn.idea360.oracle.model.Account">
        select * from account
    </select>

</mapper>

單元測試

@SpringBootTest
class AccountMapperTest {

    @Autowired
    private AccountMapper accountMapper;

    @Test
    public void insert() {
        Account account = new Account("admin", 1);
        accountMapper.insert(account);
        System.out.println(account.getId());
    }

    @Test
    public void insertBatch() {
        List<Account> data = new ArrayList<>();
        for (int i=0; i<3; i++) {
            Account account = new Account("test" + i, i+2);
            data.add(account);
        }
        accountMapper.insertBatch(data);
    }

    @Test
    public void updateIgnoreNullById() {
        Account account = new Account("admin0", 1);
        account.setId(1);
        accountMapper.updateIgnoreNullById(account);
    }

    @Test
    public void removeById() {
        accountMapper.removeById(4);
    }

    @Test
    public void selectById() {
        Account account = accountMapper.selectById(4);
        System.out.println(account.toString());
    }

    @Test
    public void selectByMap() {
        Map<String, Object> params = new HashMap<>();
        params.put("realName", "admin");
        Account account = accountMapper.selectByMap(params);
        System.out.println(account);
    }

    @Test
    public void selectByIds() {
        Integer[] ids = {1, 2};
        List<Account> accounts = accountMapper.selectByIds(ids);
        System.out.println(accounts);
    }

    @Test
    public void selectPage() {
        Page<Account> page = new Page<>(1, 10);
        HashMap<Object, Object> condition = new HashMap<>();
        condition.put("keyword", "ad");
        page.setCondition(condition);
        List<Account> accounts = accountMapper.selectPage(page);
        page.setRecords(accounts);
        System.out.println(page);
    }

    @Test
    public void listAll() {
        List<Account> accounts = accountMapper.listAll();
        System.out.println(accounts);
    }
}

最後

oracle 在自增主鍵、分頁、模糊查詢、批量操做上和 mysql 略有不一樣,上邊的例子裏基本都演示到了。初次接觸 oracle, 若有錯誤還請指出, 共同進步。同時,但願你們關注公衆號【當我趕上你】, 您的支持就是我最大的動力。

相關文章
相關標籤/搜索