最近公司的項目是基於 oracle
數據庫的,這裏記錄下 springboot+mybatis+oracle
的踩坑過程。java
version: '2' services: oracle: image: sath89/oracle-xe-11g container_name: oracle ports: - 1521:1521 - 8082:8080 volumes: - ./oracle/data:/u01/app/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"
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>
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
, 若有錯誤還請指出, 共同進步。同時,但願你們關注公衆號【當我趕上你】, 您的支持就是我最大的動力。