mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-06 16:48:24 +08:00
update docs
This commit is contained in:
parent
2f54af9122
commit
f06fa5b6df
41
docs/.vitepress/cache/deps/@theme_index.js
vendored
Normal file
41
docs/.vitepress/cache/deps/@theme_index.js
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
// node_modules/vitepress/dist/client/theme-default/index.js
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/base.css";
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
|
||||
import "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
|
||||
import VPBadge from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
|
||||
import Layout from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/Layout.vue";
|
||||
import { default as default2 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
|
||||
import { default as default3 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
|
||||
import { default as default4 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
|
||||
import { default as default5 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
|
||||
import { default as default6 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
|
||||
import { default as default7 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
|
||||
import { default as default8 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
|
||||
import { default as default9 } from "/Users/michael/work/git/mybatis-flex/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
|
||||
var theme = {
|
||||
Layout,
|
||||
enhanceApp: ({ app }) => {
|
||||
app.component("Badge", VPBadge);
|
||||
}
|
||||
};
|
||||
var without_fonts_default = theme;
|
||||
export {
|
||||
default5 as VPDocAsideSponsors,
|
||||
default3 as VPHomeFeatures,
|
||||
default2 as VPHomeHero,
|
||||
default4 as VPHomeSponsors,
|
||||
default9 as VPTeamMembers,
|
||||
default6 as VPTeamPage,
|
||||
default8 as VPTeamPageSection,
|
||||
default7 as VPTeamPageTitle,
|
||||
without_fonts_default as default
|
||||
};
|
||||
//# sourceMappingURL=@theme_index.js.map
|
||||
7
docs/.vitepress/cache/deps/@theme_index.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/@theme_index.js.map
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../../node_modules/vitepress/dist/client/theme-default/index.js", "../../../node_modules/vitepress/dist/client/theme-default/without-fonts.js"],
|
||||
"sourcesContent": ["import './styles/fonts.css';\nexport * from './without-fonts';\nexport { default as default } from './without-fonts';\n", "import './styles/vars.css';\nimport './styles/base.css';\nimport './styles/utils.css';\nimport './styles/components/custom-block.css';\nimport './styles/components/vp-code.css';\nimport './styles/components/vp-code-group.css';\nimport './styles/components/vp-doc.css';\nimport './styles/components/vp-sponsor.css';\nimport VPBadge from './components/VPBadge.vue';\nimport Layout from './Layout.vue';\n// Note: if we add more optional components here, i.e. components that are not\n// used in the theme by default unless the user imports them, make sure to update\n// the `lazyDefaultThemeComponentsRE` regex in src/node/build/bundle.ts.\nexport { default as VPHomeHero } from './components/VPHomeHero.vue';\nexport { default as VPHomeFeatures } from './components/VPHomeFeatures.vue';\nexport { default as VPHomeSponsors } from './components/VPHomeSponsors.vue';\nexport { default as VPDocAsideSponsors } from './components/VPDocAsideSponsors.vue';\nexport { default as VPTeamPage } from './components/VPTeamPage.vue';\nexport { default as VPTeamPageTitle } from './components/VPTeamPageTitle.vue';\nexport { default as VPTeamPageSection } from './components/VPTeamPageSection.vue';\nexport { default as VPTeamMembers } from './components/VPTeamMembers.vue';\nconst theme = {\n Layout,\n enhanceApp: ({ app }) => {\n app.component('Badge', VPBadge);\n }\n};\nexport default theme;\n"],
|
||||
"mappings": ";AAAA,OAAO;;;ACAP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO;AACP,OAAO,aAAa;AACpB,OAAO,YAAY;AAInB,SAAoB,WAAXA,gBAA6B;AACtC,SAAoB,WAAXA,gBAAiC;AAC1C,SAAoB,WAAXA,gBAAiC;AAC1C,SAAoB,WAAXA,gBAAqC;AAC9C,SAAoB,WAAXA,gBAA6B;AACtC,SAAoB,WAAXA,gBAAkC;AAC3C,SAAoB,WAAXA,gBAAoC;AAC7C,SAAoB,WAAXA,gBAAgC;AACzC,IAAM,QAAQ;AAAA,EACV;AAAA,EACA,YAAY,CAAC,EAAE,IAAI,MAAM;AACrB,QAAI,UAAU,SAAS,OAAO;AAAA,EAClC;AACJ;AACA,IAAO,wBAAQ;",
|
||||
"names": ["default"]
|
||||
}
|
||||
162
docs/.vitepress/cache/deps/@vue_devtools-api.js
vendored
Normal file
162
docs/.vitepress/cache/deps/@vue_devtools-api.js
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
// node_modules/@vue/devtools-api/lib/esm/env.js
|
||||
function getDevtoolsGlobalHook() {
|
||||
return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__;
|
||||
}
|
||||
function getTarget() {
|
||||
return typeof navigator !== "undefined" && typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {};
|
||||
}
|
||||
var isProxyAvailable = typeof Proxy === "function";
|
||||
|
||||
// node_modules/@vue/devtools-api/lib/esm/const.js
|
||||
var HOOK_SETUP = "devtools-plugin:setup";
|
||||
var HOOK_PLUGIN_SETTINGS_SET = "plugin:settings:set";
|
||||
|
||||
// node_modules/@vue/devtools-api/lib/esm/time.js
|
||||
var supported;
|
||||
var perf;
|
||||
function isPerformanceSupported() {
|
||||
var _a;
|
||||
if (supported !== void 0) {
|
||||
return supported;
|
||||
}
|
||||
if (typeof window !== "undefined" && window.performance) {
|
||||
supported = true;
|
||||
perf = window.performance;
|
||||
} else if (typeof global !== "undefined" && ((_a = global.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) {
|
||||
supported = true;
|
||||
perf = global.perf_hooks.performance;
|
||||
} else {
|
||||
supported = false;
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
function now() {
|
||||
return isPerformanceSupported() ? perf.now() : Date.now();
|
||||
}
|
||||
|
||||
// node_modules/@vue/devtools-api/lib/esm/proxy.js
|
||||
var ApiProxy = class {
|
||||
constructor(plugin, hook) {
|
||||
this.target = null;
|
||||
this.targetQueue = [];
|
||||
this.onQueue = [];
|
||||
this.plugin = plugin;
|
||||
this.hook = hook;
|
||||
const defaultSettings = {};
|
||||
if (plugin.settings) {
|
||||
for (const id in plugin.settings) {
|
||||
const item = plugin.settings[id];
|
||||
defaultSettings[id] = item.defaultValue;
|
||||
}
|
||||
}
|
||||
const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`;
|
||||
let currentSettings = Object.assign({}, defaultSettings);
|
||||
try {
|
||||
const raw = localStorage.getItem(localSettingsSaveId);
|
||||
const data = JSON.parse(raw);
|
||||
Object.assign(currentSettings, data);
|
||||
} catch (e) {
|
||||
}
|
||||
this.fallbacks = {
|
||||
getSettings() {
|
||||
return currentSettings;
|
||||
},
|
||||
setSettings(value) {
|
||||
try {
|
||||
localStorage.setItem(localSettingsSaveId, JSON.stringify(value));
|
||||
} catch (e) {
|
||||
}
|
||||
currentSettings = value;
|
||||
},
|
||||
now() {
|
||||
return now();
|
||||
}
|
||||
};
|
||||
if (hook) {
|
||||
hook.on(HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => {
|
||||
if (pluginId === this.plugin.id) {
|
||||
this.fallbacks.setSettings(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.proxiedOn = new Proxy({}, {
|
||||
get: (_target, prop) => {
|
||||
if (this.target) {
|
||||
return this.target.on[prop];
|
||||
} else {
|
||||
return (...args) => {
|
||||
this.onQueue.push({
|
||||
method: prop,
|
||||
args
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
this.proxiedTarget = new Proxy({}, {
|
||||
get: (_target, prop) => {
|
||||
if (this.target) {
|
||||
return this.target[prop];
|
||||
} else if (prop === "on") {
|
||||
return this.proxiedOn;
|
||||
} else if (Object.keys(this.fallbacks).includes(prop)) {
|
||||
return (...args) => {
|
||||
this.targetQueue.push({
|
||||
method: prop,
|
||||
args,
|
||||
resolve: () => {
|
||||
}
|
||||
});
|
||||
return this.fallbacks[prop](...args);
|
||||
};
|
||||
} else {
|
||||
return (...args) => {
|
||||
return new Promise((resolve) => {
|
||||
this.targetQueue.push({
|
||||
method: prop,
|
||||
args,
|
||||
resolve
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
async setRealTarget(target) {
|
||||
this.target = target;
|
||||
for (const item of this.onQueue) {
|
||||
this.target.on[item.method](...item.args);
|
||||
}
|
||||
for (const item of this.targetQueue) {
|
||||
item.resolve(await this.target[item.method](...item.args));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// node_modules/@vue/devtools-api/lib/esm/index.js
|
||||
function setupDevtoolsPlugin(pluginDescriptor, setupFn) {
|
||||
const descriptor = pluginDescriptor;
|
||||
const target = getTarget();
|
||||
const hook = getDevtoolsGlobalHook();
|
||||
const enableProxy = isProxyAvailable && descriptor.enableEarlyProxy;
|
||||
if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) {
|
||||
hook.emit(HOOK_SETUP, pluginDescriptor, setupFn);
|
||||
} else {
|
||||
const proxy = enableProxy ? new ApiProxy(descriptor, hook) : null;
|
||||
const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || [];
|
||||
list.push({
|
||||
pluginDescriptor: descriptor,
|
||||
setupFn,
|
||||
proxy
|
||||
});
|
||||
if (proxy)
|
||||
setupFn(proxy.proxiedTarget);
|
||||
}
|
||||
}
|
||||
export {
|
||||
isPerformanceSupported,
|
||||
now,
|
||||
setupDevtoolsPlugin
|
||||
};
|
||||
//# sourceMappingURL=@vue_devtools-api.js.map
|
||||
7
docs/.vitepress/cache/deps/@vue_devtools-api.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/@vue_devtools-api.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
25
docs/.vitepress/cache/deps/_metadata.json
vendored
Normal file
25
docs/.vitepress/cache/deps/_metadata.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"hash": "14110bcc",
|
||||
"browserHash": "8dc88e09",
|
||||
"optimized": {
|
||||
"vue": {
|
||||
"src": "../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
|
||||
"file": "vue.js",
|
||||
"fileHash": "a62e771b",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@vue/devtools-api": {
|
||||
"src": "../../../node_modules/@vue/devtools-api/lib/esm/index.js",
|
||||
"file": "@vue_devtools-api.js",
|
||||
"fileHash": "d5c641bb",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@theme/index": {
|
||||
"src": "../../../node_modules/vitepress/dist/client/theme-default/index.js",
|
||||
"file": "@theme_index.js",
|
||||
"fileHash": "0ec9b2ee",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
"chunks": {}
|
||||
}
|
||||
1
docs/.vitepress/cache/deps/package.json
vendored
Normal file
1
docs/.vitepress/cache/deps/package.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"type":"module"}
|
||||
9516
docs/.vitepress/cache/deps/vue.js
vendored
Normal file
9516
docs/.vitepress/cache/deps/vue.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
docs/.vitepress/cache/deps/vue.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/vue.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
86
docs/.vitepress/config.ts
Normal file
86
docs/.vitepress/config.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "Mybatis-Flex",
|
||||
description: "MyBatis-Flex Office website",
|
||||
// logo: '/assets/images/logo02.png',
|
||||
|
||||
themeConfig: {
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{ text: '首页', link: '/' },
|
||||
{ text: '帮助文档', link: '/zh/maven' },
|
||||
{ text: '更新日志', link: 'https://gitee.com/mybatis-flex/mybatis-flex/blob/main/changes.txt' },
|
||||
{ text: '源码', items: [
|
||||
{ text: 'Gitee', link: 'https://gitee.com/mybatis-flex/mybatis-flex' },
|
||||
{ text: 'Github', link: 'https://github.com/mybatis-flex/mybatis-flex' }
|
||||
] },
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: '简介',
|
||||
items: [
|
||||
{ text: 'Mybatis-Flex 是什么', link: '/zh/what-is-mybatisflex' },
|
||||
{ text: '快速开始', link: '/zh/getting-started' },
|
||||
{ text: 'Maven 依赖', link: '/zh/maven' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '基础功能',
|
||||
items: [
|
||||
{ text: '增删改', link: '/zh/add-delete-update' },
|
||||
{ text: '查询和分页', link: '/zh/query' },
|
||||
{ text: 'QueryWrapper', link: '/zh/querywrapper' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '核心功能',
|
||||
items: [
|
||||
{ text: '实体类配置', link: '/zh/table' },
|
||||
{ text: '主键配置', link: '/zh/id' },
|
||||
{ text: '列配置', link: '/zh/column' },
|
||||
{ text: 'Db + Row', link: '/zh/db_row' },
|
||||
{ text: '逻辑删除', link: '/zh/logic_delete' },
|
||||
{ text: '乐观锁', link: '/zh/version' },
|
||||
{ text: '数据填充', link: '/zh/fill' },
|
||||
{ text: '数据脱敏', link: '/zh/mask' },
|
||||
{ text: '数据审计', link: '/zh/audit' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '其他',
|
||||
items: [
|
||||
{ text: '代码生成器', link: '/zh/codegen' },
|
||||
{ text: 'APT 设置', link: '/zh/apt' },
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
footer: {
|
||||
message: 'Released under the Apache License.',
|
||||
copyright: 'Copyright © 2022-present Mybatis-Flex '
|
||||
}
|
||||
},
|
||||
head: [
|
||||
[
|
||||
'link',{ rel: 'icon', href: '/assets/images/logo02.png' }
|
||||
],
|
||||
|
||||
[
|
||||
// 添加百度统计
|
||||
"script",
|
||||
{},
|
||||
`
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?3f50d5fbe3bf955411748b5616b24a24";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
`
|
||||
]
|
||||
],
|
||||
})
|
||||
BIN
docs/assets/images/logo01.png
Normal file
BIN
docs/assets/images/logo01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
BIN
docs/assets/images/logo02.png
Normal file
BIN
docs/assets/images/logo02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
28
docs/index.md
Normal file
28
docs/index.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: "Mybatis-Flex"
|
||||
text: "一个优雅的 Mybatis 增强框架"
|
||||
tagline: 更轻量、更灵活、更简单
|
||||
image:
|
||||
src: /assets/images/logo01.png
|
||||
alt: Mybatis-Flex
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 快速开始
|
||||
link: /zh/getting-started
|
||||
- theme: alt
|
||||
text: 在 Gitee 上查看
|
||||
link: https://gitee.com/mybatis-flex/mybatis-flex
|
||||
|
||||
features:
|
||||
- title: 更轻量
|
||||
details: Mybatis-Flex 框架基于 Mybatis 的 SqlProvider 进行实现,没有任何连拦截器,没有任何第三方依赖,没有任何 Sql Parse,因此也会有更高的性能。
|
||||
- title: 更灵活
|
||||
details: Mybatis-Flex 提供了非常灵活的 QueryWrapper,支持关联查询、多表查询、多主键、逻辑删除、乐观锁更新、数据填充、数据脱敏....
|
||||
- title: 更简单
|
||||
details: 完善的增删改查和分页查询,内置功能强劲的代码生成器,SQL 查询 IDE 自动提示...
|
||||
---
|
||||
|
||||
10
docs/package.json
Normal file
10
docs/package.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev",
|
||||
"docs:build": "vitepress build",
|
||||
"docs:preview": "vitepress preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.0.0-alpha.61"
|
||||
}
|
||||
}
|
||||
77
docs/zh/add-delete-update.md
Normal file
77
docs/zh/add-delete-update.md
Normal file
@ -0,0 +1,77 @@
|
||||
# Mybatis-Flex 的增删改功能
|
||||
|
||||
Mybatis-Flex 内置了一个名为 `BaseMapper` 的接口,它实现了基本的增删改查功能以及分页查询功能。
|
||||
|
||||
> Mybatis-Flex 的 **代码生成器** 生成的所有 Mapper 辅助类,都是继承 BaseMapper。
|
||||
|
||||
## 新增数据
|
||||
|
||||
`BaseMapper` 的接口提供了 insert 和 insertBatch 方法,用于新增数据;
|
||||
|
||||
- **insert**: 新增 1 条数据
|
||||
- **insertBatch**: 新增多条数据
|
||||
|
||||
|
||||
## 删除数据
|
||||
|
||||
`BaseMapper` 的接口提供了 deleteById、deleteBatchByIds、deleteByMap、deleteByQuery 方法,用于删除数据;
|
||||
|
||||
- **deleteById(id)** :根据主键 id 删除数据,复合主键需要传入一个数组,例如 [1,100]
|
||||
- **deleteBatchByIds(idList)** :根据主键的 集合,批量删除多条数据
|
||||
- **deleteByMap(map)** :根据 `map<字段名,值>` 组成的条件删除数据,字段名和值的关系为相等的关系,同时,防止 "不小心" 全表
|
||||
删除数据,map 的值不允许为 null 或者 空数据。
|
||||
- **deleteByQuery(queryWrapper)**:根据 queryWrapper 组成的条件删除数据。
|
||||
|
||||
|
||||
**deleteByQuery(queryWrapper)** 方法示例:
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
queryWrapper.where(ACCOUNT.ID.ge(100));
|
||||
|
||||
//通过 queryWrapper 删除
|
||||
accountMapper.deleteByQuery(queryWrapper);
|
||||
```
|
||||
以上的代码,会删除所有 id >= 100 的数据,其执行的 Sql 如下:
|
||||
|
||||
```sql
|
||||
delete from tb_account where id >= 100;
|
||||
```
|
||||
|
||||
>tip: QueryWrapper 非常灵活,也是 Mybatis-Flex 的特色之一,更多关于 QueryWrapper 的
|
||||
> 请看 [QueryWrapper 章节](./querywrapper)。
|
||||
|
||||
## 更新数据
|
||||
|
||||
`BaseMapper` 的接口提供了 update、updateByMap、updateByQuery 方法,用于更新数据;
|
||||
|
||||
- **update(entity)**:根据主键更新到 entity 到数据库,要求主键值不能为空,否则会抛出异常。同时,数据为 null 的字段 **不会** 更新到数据库。
|
||||
- **update(entity, ignoreNulls)**:根据主键更新到 entity 到数据库,要求主键值不能为空。ignoreNulls 为是否忽略 null 字段,如果为 true,所有 null 字段都会更新到数据库。
|
||||
- **updateByMap(entity, map)**:根据 `map<字段名,值>` 组成的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略), entity 的 null 属性,会自动被忽略。
|
||||
- **updateByQuery(entity, queryWrapper)**:根据 queryWrapper 组成的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略), entity 的 null 属性,会自动被忽略。
|
||||
- **updateByQuery(entity, ignoreNulls, queryWrapper)**:据 queryWrapper 组成的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略)。 ignoreNulls 用于是否忽略 entity 的 null 属性
|
||||
, 若 ignoreNulls 为 true,entity 的所有 null 属性都会被更新到数据库。
|
||||
|
||||
|
||||
## 部分字段更新
|
||||
|
||||
在很多场景下,我们希望只更新**部分字段**,而更新的字段中,一些为 null,一些非 null。此时需要用到 `UpdateEntity` 工具类,以下是示例代码:
|
||||
|
||||
```java
|
||||
Account account = UpdateEntity.of(Account.class);
|
||||
account.setId(100);
|
||||
account.setUserName(null);
|
||||
account.setAge(10);
|
||||
|
||||
accountMapper.update(account,false);
|
||||
```
|
||||
|
||||
以上的示例中,会把 id (主键)为 100 这条数据中的 user_name 字段更新为 null,age 字段更新为 10,其他字段不会被更新。也就是说,通过 UpdateEntity 创建的对象,只会更新调用了 setter 方法的字段,若不调用 setter 方法,不管这个对象里的属性的值是什么,都不会更新到数据库。
|
||||
|
||||
其执行的 sql 内容如下:
|
||||
|
||||
```sql
|
||||
update tb_account
|
||||
set user_name = ?, age = ? where id = ?
|
||||
#参数: null,10,100
|
||||
```
|
||||
0
docs/zh/basemapper.md
Normal file
0
docs/zh/basemapper.md
Normal file
169
docs/zh/fill.md
Normal file
169
docs/zh/fill.md
Normal file
@ -0,0 +1,169 @@
|
||||
# Entity 的主键配置
|
||||
|
||||
在 Entity 类中,Mybatis-Flex 是使用 `@Id` 注解来标识主键的,如下代码所示:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
// id 为自增主键
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Long id;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
|
||||
`@Id` 注解的内容如下:
|
||||
|
||||
```java
|
||||
public @interface Id {
|
||||
|
||||
/**
|
||||
* ID 生成策略,默认为 none
|
||||
*
|
||||
* @return 生成策略
|
||||
*/
|
||||
KeyType keyType() default KeyType.None;
|
||||
|
||||
/**
|
||||
* 若 keyType 类型是 sequence, value 则代表的是
|
||||
* sequence 序列的 sql 内容
|
||||
* 例如:select SEQ_USER_ID.nextval as id from dual
|
||||
*
|
||||
* 若 keyType 是 Generator,value 则代表的是使用的那个 keyGenerator 的名称
|
||||
*
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
|
||||
/**
|
||||
* sequence 序列执行顺序
|
||||
* 是在 entity 数据插入之前执行,还是之后执行,之后执行的一般是数据主动生成的 id
|
||||
*
|
||||
* @return 执行之前还是之后
|
||||
*/
|
||||
boolean before() default true;
|
||||
}
|
||||
```
|
||||
|
||||
keyType 为主键的生成方式,KeyType 有 4 种类型:
|
||||
|
||||
```java
|
||||
public enum KeyType {
|
||||
|
||||
/**
|
||||
* 自增的方式
|
||||
*/
|
||||
Auto,
|
||||
|
||||
/**
|
||||
* 通过执行数据库 sql 生成
|
||||
* 例如:select SEQ_USER_ID.nextval as id from dual
|
||||
*/
|
||||
Sequence,
|
||||
|
||||
/**
|
||||
* 通过 IKeyGenerator 生成器生成
|
||||
*/
|
||||
Generator,
|
||||
|
||||
/**
|
||||
* 其他方式,比如说在代码层用户手动设置
|
||||
*/
|
||||
None,
|
||||
}
|
||||
```
|
||||
|
||||
## 多主键、复合主键
|
||||
|
||||
Mybatis-Flex 多主键就是在 Entity 类里有多个 `@Id` 注解标识而已,比如:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Auto)
|
||||
private Long id;
|
||||
|
||||
@Id(keyType=KeyType.Generator, value="uuid")
|
||||
private String otherId;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
当我们保存数据的时候,Account 的 id 主键为自增,而 otherId 主键则通过 uuid 生成。
|
||||
|
||||
## 主键生成器
|
||||
|
||||
第 1 步:编写一个类,实现 `IKeyGenerator` 接口,例如:
|
||||
|
||||
```java
|
||||
public class UUIDKeyGenerator implements IKeyGenerator {
|
||||
|
||||
@Override
|
||||
public Object generate(Object entity, String keyColumn) {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
第 2 步:注册 UUIDKeyGenerator
|
||||
|
||||
```java
|
||||
KeyGeneratorFactory.register("myUUID", new UUIDKeyGenerator());
|
||||
```
|
||||
|
||||
第 3 步:在 Entity 里使用 "myUUID" 生成器:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Generator, value="myUUID")
|
||||
private String otherId;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 使用序列 Sequence 生成
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Sequence, value="select SEQ_USER_ID.nextval as id from dual")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## 全局配置
|
||||
|
||||
一般的项目中,通常是许多的 Entity 使用同一个数据库,同时使用一种主键生成方式,比如说都使用 自增,
|
||||
或者都使用通过序列(Sequence)生成,此时,我们是没有必要为每个 Entity 单独配置一样内容的。
|
||||
|
||||
Mybatis-Flex 提供了一种全局配置的方式,代码如下:
|
||||
|
||||
```java
|
||||
FlexGlobalConfig.KeyConfig keyConfig = new FlexGlobalConfig.KeyConfig();
|
||||
keyConfig.setKeyType(KeyType.Sequence);
|
||||
keyConfig.setValue("select SEQ_USER_ID.nextval as id from dual")
|
||||
keyConfig.setBefore(true);
|
||||
|
||||
FlexGlobalConfig.getDefaultConfig().setKeyConfig(keyConfig);
|
||||
```
|
||||
|
||||
此时,Entity 类 Account.java 只需要如下配置即可。
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id()
|
||||
private Long id;
|
||||
|
||||
}
|
||||
```
|
||||
85
docs/zh/getting-started.md
Normal file
85
docs/zh/getting-started.md
Normal file
@ -0,0 +1,85 @@
|
||||
# 快速开始
|
||||
|
||||
## Hello World
|
||||
|
||||
**第 1 步:创建数据库表**
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS `tb_account`
|
||||
(
|
||||
`id` INTEGER PRIMARY KEY auto_increment,
|
||||
`user_name` VARCHAR(100),
|
||||
`age` Integer,
|
||||
`birthday` DATETIME
|
||||
);
|
||||
```
|
||||
|
||||
**第 2 步:创建 java 项目,并添加 Maven 依赖**
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-core</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
**第 3 步:编写实体类**
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Long id;
|
||||
private String userName;
|
||||
private Integer age;
|
||||
private Date birthday;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
- `@Table("tb_account")` 设置实体类与表名的映射关系
|
||||
- `@Id(keyType = KeyType.Auto)` 标识主键为自增
|
||||
|
||||
**第 4 步:编写一个 main 方法开始使用**
|
||||
|
||||
```java
|
||||
public class HelloWorld {
|
||||
public static void main(String... args) {
|
||||
|
||||
//创建数据源
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/mybatis-flex");
|
||||
dataSource.setUsername("username");
|
||||
dataSource.setPassword("password");
|
||||
|
||||
//配置数据源
|
||||
MybatisFlexBootstrap.getInstance()
|
||||
.setDatasource(dataSource)
|
||||
.addMapper(AccountMapper.class)
|
||||
.start();
|
||||
|
||||
|
||||
//示例1:查询 id=1 条数据
|
||||
Account account = MybatisFlexBootstrap.getInstance()
|
||||
.execute(AccountMapper.class, mapper ->
|
||||
mapper.selectOneById(1)
|
||||
);
|
||||
|
||||
//示例2:或者使用 Db + Row 查询
|
||||
String sql = "select * from tb_account where age > ?";
|
||||
List<Row> rows = Db.selectListBySql(sql, 18);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 以上的示例中, `AccountMapper.class` 为 Mybatis-Flex 通过 APT 自动生成,无需手动编码。
|
||||
> 也可以关闭自动生成功能,手动编写 AccountMapper,更多查看 [APT 文档](/zh/apt)。
|
||||
|
||||
|
||||
## 更多示例
|
||||
|
||||
- 示例 1:[Mybatis-Flex 原生(非 Spring)](https://gitee.com/mybatis-flex/mybatis-flex/tree/main/mybatis-flex-test/mybatis-flex-native-test)
|
||||
- 示例 2:[Mybatis-Flex with Spring]()
|
||||
- 示例 3:[Mybatis-Flex with Spring boot]()
|
||||
- 示例 4:[Db + Row]()
|
||||
169
docs/zh/mask.md
Normal file
169
docs/zh/mask.md
Normal file
@ -0,0 +1,169 @@
|
||||
# Entity 的主键配置
|
||||
|
||||
在 Entity 类中,Mybatis-Flex 是使用 `@Id` 注解来标识主键的,如下代码所示:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
// id 为自增主键
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Long id;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
|
||||
`@Id` 注解的内容如下:
|
||||
|
||||
```java
|
||||
public @interface Id {
|
||||
|
||||
/**
|
||||
* ID 生成策略,默认为 none
|
||||
*
|
||||
* @return 生成策略
|
||||
*/
|
||||
KeyType keyType() default KeyType.None;
|
||||
|
||||
/**
|
||||
* 若 keyType 类型是 sequence, value 则代表的是
|
||||
* sequence 序列的 sql 内容
|
||||
* 例如:select SEQ_USER_ID.nextval as id from dual
|
||||
*
|
||||
* 若 keyType 是 Generator,value 则代表的是使用的那个 keyGenerator 的名称
|
||||
*
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
|
||||
/**
|
||||
* sequence 序列执行顺序
|
||||
* 是在 entity 数据插入之前执行,还是之后执行,之后执行的一般是数据主动生成的 id
|
||||
*
|
||||
* @return 执行之前还是之后
|
||||
*/
|
||||
boolean before() default true;
|
||||
}
|
||||
```
|
||||
|
||||
keyType 为主键的生成方式,KeyType 有 4 种类型:
|
||||
|
||||
```java
|
||||
public enum KeyType {
|
||||
|
||||
/**
|
||||
* 自增的方式
|
||||
*/
|
||||
Auto,
|
||||
|
||||
/**
|
||||
* 通过执行数据库 sql 生成
|
||||
* 例如:select SEQ_USER_ID.nextval as id from dual
|
||||
*/
|
||||
Sequence,
|
||||
|
||||
/**
|
||||
* 通过 IKeyGenerator 生成器生成
|
||||
*/
|
||||
Generator,
|
||||
|
||||
/**
|
||||
* 其他方式,比如说在代码层用户手动设置
|
||||
*/
|
||||
None,
|
||||
}
|
||||
```
|
||||
|
||||
## 多主键、复合主键
|
||||
|
||||
Mybatis-Flex 多主键就是在 Entity 类里有多个 `@Id` 注解标识而已,比如:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Auto)
|
||||
private Long id;
|
||||
|
||||
@Id(keyType=KeyType.Generator, value="uuid")
|
||||
private String otherId;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
当我们保存数据的时候,Account 的 id 主键为自增,而 otherId 主键则通过 uuid 生成。
|
||||
|
||||
## 主键生成器
|
||||
|
||||
第 1 步:编写一个类,实现 `IKeyGenerator` 接口,例如:
|
||||
|
||||
```java
|
||||
public class UUIDKeyGenerator implements IKeyGenerator {
|
||||
|
||||
@Override
|
||||
public Object generate(Object entity, String keyColumn) {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
第 2 步:注册 UUIDKeyGenerator
|
||||
|
||||
```java
|
||||
KeyGeneratorFactory.register("myUUID", new UUIDKeyGenerator());
|
||||
```
|
||||
|
||||
第 3 步:在 Entity 里使用 "myUUID" 生成器:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Generator, value="myUUID")
|
||||
private String otherId;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 使用序列 Sequence 生成
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Sequence, value="select SEQ_USER_ID.nextval as id from dual")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## 全局配置
|
||||
|
||||
一般的项目中,通常是许多的 Entity 使用同一个数据库,同时使用一种主键生成方式,比如说都使用 自增,
|
||||
或者都使用通过序列(Sequence)生成,此时,我们是没有必要为每个 Entity 单独配置一样内容的。
|
||||
|
||||
Mybatis-Flex 提供了一种全局配置的方式,代码如下:
|
||||
|
||||
```java
|
||||
FlexGlobalConfig.KeyConfig keyConfig = new FlexGlobalConfig.KeyConfig();
|
||||
keyConfig.setKeyType(KeyType.Sequence);
|
||||
keyConfig.setValue("select SEQ_USER_ID.nextval as id from dual")
|
||||
keyConfig.setBefore(true);
|
||||
|
||||
FlexGlobalConfig.getDefaultConfig().setKeyConfig(keyConfig);
|
||||
```
|
||||
|
||||
此时,Entity 类 Account.java 只需要如下配置即可。
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id()
|
||||
private Long id;
|
||||
|
||||
}
|
||||
```
|
||||
59
docs/zh/query.md
Normal file
59
docs/zh/query.md
Normal file
@ -0,0 +1,59 @@
|
||||
# Mybatis-Flex 的查询和分页
|
||||
|
||||
## 基础查询
|
||||
|
||||
在 Mybatis-Flex 的 BaseMapper 中,提供了如下的功能用于查询数据库的数据:
|
||||
|
||||
- **selectOneById(id)**:根据主键 id 查询数据
|
||||
- **selectOneByMap(map)**:根据 `map<字段名,值>` 组成的条件查询 1 条数据,若命中多条数据,则只返回第一条数据。
|
||||
- **selectOneByQuery(query)**:根据 QueryWrapper 组成的条件查询 1 条数据,若命中多条数据,则只返回第一条数据。
|
||||
- **selectListByIds(idList)**:根据多个 id 查询,返回多条数据
|
||||
- **selectListByMap(map)**:根据 `map<字段名,值>` 组成的条件查询数据。
|
||||
- **selectListByMap(map, count)**:根据 `map<字段名,值>` 组成的条件查询数据,只取前 count 条。
|
||||
- **selectListByQuery(query)**: 根据 QueryWrapper 组成的条件查询数据。
|
||||
- **selectAll**:查询所有数据。
|
||||
- **selectCountByQuery**:根据 QueryWrapper 查询数据量。
|
||||
|
||||
## 分页查询
|
||||
|
||||
在 Mybatis-Flex 的 BaseMapper 中,提供了如下的分页查询功能:
|
||||
|
||||
```java
|
||||
Page<T> paginate(int pageNumber, int pageSize, QueryWrapper queryWrapper);
|
||||
```
|
||||
- pageNumber: 当前页码,从 1 开始
|
||||
- pageSize: 每 1 页的数据量
|
||||
- queryWrapper: 查询条件
|
||||
|
||||
paginate 的返回值为 Page 对象,Page 类的定义如下:
|
||||
|
||||
```java
|
||||
public class Page<T> implements Serializable {
|
||||
private List<T> list; // list result of this page
|
||||
private int pageNumber; // page number
|
||||
private int pageSize; // result amount of this page
|
||||
private long totalPage; // total page
|
||||
private long totalRow; // total row
|
||||
}
|
||||
```
|
||||
|
||||
在 Page 的定义中,我们知道:通过 `paginate` 方法去查询数据的时候,除了数据列表以外,还查询的数据的总量,才能构造出 `Page` 对象。
|
||||
|
||||
|
||||
在一般的分页场景中,只有第一页的时候有必要去查询数据总量,第二页以后是没必要的(因为第一页已经拿到总量了),因此,Mybatis-Flex 的分页查询还提供了另一个方法:
|
||||
|
||||
```java
|
||||
Page<T> paginate(Page<T> page, QueryWrapper queryWrapper);
|
||||
```
|
||||
|
||||
这个方法的使用示例如下:
|
||||
|
||||
```java
|
||||
// 多一个 totalPage 参数
|
||||
Page<T> page = new Page<>(pageNumber, pageSize, totalPage);
|
||||
Page<T> resultPage = paginate(page, queryWrapper);
|
||||
```
|
||||
当构造的 `page` 对象已经有 totalPage 后,再通过 `paginate(page, queryWrapper)` 方法去查询,则不会再查询数据总量,从提高了性能。
|
||||
|
||||
> 只有 totalRow 小于 0 的时候才会去查询总量。
|
||||
|
||||
360
docs/zh/querywrapper.md
Normal file
360
docs/zh/querywrapper.md
Normal file
@ -0,0 +1,360 @@
|
||||
# 灵活的 QueryWrapper
|
||||
在 [增删改](./add-delete-update) 和 [查询和分页](./query) 章节中,我们随时能看到 QueryWrapper 的身影,QueryWrapper 是用于构造 Sql 的
|
||||
强有力工具,也是 Mybatis-Flex 的亮点和特色。
|
||||
|
||||
::: tip 提示
|
||||
QueryWrapper 可以被序列化通过 RPC 进行传输,因此,在微服务项目中,我们可以在客户端(网关、Controller 层等)构造出 QueryWrapper,传给
|
||||
Provider 层进行查询返回数据。
|
||||
:::
|
||||
|
||||
## QueryWrapper 的使用
|
||||
|
||||
以下代码是一个完整 Spring Controller 的示例:
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class AccountController {
|
||||
|
||||
@Autowired
|
||||
AccountMapper accountMapper;
|
||||
|
||||
@GetMapping("/accounts")
|
||||
List<Account> selectList() {
|
||||
|
||||
//构造 QueryWrapper
|
||||
QueryWrapper query = new QueryWrapper();
|
||||
query.where(ACCOUNT.ID.ge(100));
|
||||
|
||||
//通过 query 查询数据列表返回
|
||||
return accountMapper.selectListByQuery(query);
|
||||
}
|
||||
}
|
||||
```
|
||||
在以上的示例中,其核心代码为:构造 QueryWrapper,通过 Mapper 查询,如下所示:
|
||||
|
||||
```java
|
||||
//构造 QueryWrapper
|
||||
QueryWrapper query = new QueryWrapper();
|
||||
query.where(ACCOUNT.ID.ge(100));
|
||||
|
||||
//通过 query 查询数据列表
|
||||
accountMapper.selectListByQuery(query);
|
||||
```
|
||||
以上代码执行的 Sql 如下:
|
||||
|
||||
```sql
|
||||
select * from tb_account
|
||||
where id >= 100
|
||||
```
|
||||
|
||||
|
||||
## select *
|
||||
|
||||
```java
|
||||
QueryWrapper query=new QueryWrapper();
|
||||
query.select(ACCOUNT.ID, ACCOUNT.USER_NAME)
|
||||
.from(ACCOUNT)
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT id, user_name FROM tb_account
|
||||
```
|
||||
|
||||
## select ... as
|
||||
|
||||
```java
|
||||
QueryWrapper query = new QueryWrapper()
|
||||
.select(
|
||||
ACCOUNT.ID.as("accountId")
|
||||
, ACCOUNT.USER_NAME
|
||||
.from(ACCOUNT.as("a"));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT a.id as accountId, a.user_name
|
||||
FROM tb_account AS a
|
||||
```
|
||||
|
||||
## select 多张表
|
||||
|
||||
```java
|
||||
QueryWrapper query = new QueryWrapper()
|
||||
.select(
|
||||
ACCOUNT.ID
|
||||
, ACCOUNT.USER_NAME
|
||||
, ARTICLE.ID.as("articleId")
|
||||
, ARTICLE.TITLE)
|
||||
.from(ACCOUNT.as("a"), ARTICLE.as("b"))
|
||||
.where(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT a.id, a.user_name, b.id AS articleId, b.title
|
||||
FROM tb_account AS a, tb_article AS b
|
||||
WHERE a.id = b.account_id
|
||||
```
|
||||
|
||||
## select function
|
||||
|
||||
```java
|
||||
QueryWrapper query=new QueryWrapper()
|
||||
.select(
|
||||
ACCOUNT.ID,
|
||||
ACCOUNT.USER_NAME,
|
||||
max(ACCOUNT.BIRTHDAY),
|
||||
avg(ACCOUNT.SEX).as("sex_avg")
|
||||
).from(ACCOUNT);
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT id, user_name, MAX(birthday), AVG(sex) AS sex_avg
|
||||
FROM tb_account
|
||||
```
|
||||
|
||||
## where
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper=QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.where(ACCOUNT.ID.ge(100))
|
||||
.and(ACCOUNT.USER_NAME.like("michael"));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
WHERE id >= ?
|
||||
AND user_name LIKE ?
|
||||
```
|
||||
|
||||
## where 动态条件 1
|
||||
|
||||
```java 1,4
|
||||
boolean flag = false;
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.select().from(ACCOUNT)
|
||||
.where(flag ? ACCOUNT.ID.ge(100) : noCondition())
|
||||
.and(ACCOUNT.USER_NAME.like("michael"));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
WHERE user_name LIKE ?
|
||||
```
|
||||
|
||||
## where 动态条件 2
|
||||
|
||||
```java 1,4
|
||||
boolean flag = false;
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.select().from(ACCOUNT)
|
||||
.where(ACCOUNT.ID.ge(100).when(flag)) // when....
|
||||
.and(ACCOUNT.USER_NAME.like("michael"));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
WHERE user_name LIKE ?
|
||||
```
|
||||
|
||||
## where select
|
||||
```java
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.where(ACCOUNT.ID.ge(
|
||||
select(ARTICLE.ACCOUNT_ID).from(ARTICLE).where(ARTICLE.ID.ge(100))
|
||||
));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
WHERE id >=
|
||||
(SELECT account_id FROM tb_article WHERE id >= ? )
|
||||
```
|
||||
|
||||
## where exists, not exists
|
||||
```java
|
||||
QueryWrapper queryWrapper=QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.where(ACCOUNT.ID.ge(100))
|
||||
.and(
|
||||
exist( // or notExist(...)
|
||||
selectOne().from(ARTICLE).where(ARTICLE.ID.ge(100))
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
WHERE id >= ?
|
||||
AND EXIST (
|
||||
SELECT 1 FROM tb_article WHERE id >= ?
|
||||
)
|
||||
```
|
||||
|
||||
## and (...) or (...)
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper=QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.where(ACCOUNT.ID.ge(100))
|
||||
.and(ACCOUNT.SEX.eq(1).or(ACCOUNT.SEX.eq(2)))
|
||||
.or(ACCOUNT.AGE.in(18,19,20).and(ACCOUNT.USER_NAME.like("michael")));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
WHERE id >= ?
|
||||
AND (sex = ? OR sex = ? )
|
||||
OR (age IN (?,?,?) AND user_name LIKE ? )
|
||||
```
|
||||
|
||||
## group by
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper=QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.groupBy(ACCOUNT.USER_NAME);
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
GROUP BY user_name
|
||||
```
|
||||
|
||||
## having
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper=QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.groupBy(ACCOUNT.USER_NAME)
|
||||
.having(ACCOUNT.AGE.between(18,25));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
GROUP BY user_name
|
||||
HAVING age BETWEEN ? AND ?
|
||||
```
|
||||
|
||||
## orderBy
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper=QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.orderBy(ACCOUNT.AGE.asc(), ACCOUNT.USER_NAME.desc().nullsLast());
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
ORDER BY age ASC, user_name DESC NULLS LAST
|
||||
```
|
||||
|
||||
## join(left join,inner join...)
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper=QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.leftJoin(ARTICLE).on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
|
||||
.innerJoin(ARTICLE).on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
|
||||
.where(ACCOUNT.AGE.ge(10));
|
||||
```
|
||||
|
||||
其查询生成的 Sql 如下:
|
||||
|
||||
```sql
|
||||
SELECT * FROM tb_account
|
||||
LEFT JOIN tb_article ON tb_account.id = tb_article.account_id
|
||||
INNER JOIN tb_article ON tb_account.id = tb_article.account_id
|
||||
WHERE tb_account.age >= ?
|
||||
```
|
||||
|
||||
## limit... offset
|
||||
|
||||
::: tip 提示
|
||||
在 "limit... offset" 的示例中,Mybatis-Flex 能够自动识别当前数据库,并根据数据库的类型生成不同的 SQL,用户也可以很轻易的通过 DialectFactory 注册(新增或改写)自己的实现方言。
|
||||
:::
|
||||
|
||||
|
||||
```java
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.select()
|
||||
.from(ACCOUNT)
|
||||
.orderBy(ACCOUNT.ID.desc())
|
||||
.limit(10)
|
||||
.offset(20);
|
||||
```
|
||||
|
||||
MySql 下执行的代码如下:
|
||||
```sql
|
||||
SELECT * FROM `tb_account` ORDER BY `id` DESC LIMIT 20, 10
|
||||
```
|
||||
|
||||
PostgreSQL 下执行的代码如下:
|
||||
```sql
|
||||
SELECT * FROM "tb_account" ORDER BY "id" DESC LIMIT 20 OFFSET 10
|
||||
```
|
||||
Informix 下执行的代码如下:
|
||||
```sql
|
||||
SELECT SKIP 20 FIRST 10 * FROM "tb_account" ORDER BY "id" DESC
|
||||
```
|
||||
|
||||
Oracle 下执行的代码如下:
|
||||
```sql
|
||||
SELECT * FROM (SELECT TEMP_DATAS.*,
|
||||
ROWNUM RN FROM (
|
||||
SELECT * FROM "tb_account" ORDER BY "id" DESC)
|
||||
TEMP_DATAS WHERE ROWNUM <=30)
|
||||
WHERE RN >20
|
||||
```
|
||||
|
||||
Db2 下执行的代码如下:
|
||||
```sql
|
||||
SELECT * FROM "tb_account" ORDER BY "id" DESC
|
||||
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
|
||||
```
|
||||
|
||||
Sybase 下执行的代码如下:
|
||||
```sql
|
||||
SELECT TOP 10 START AT 21 * FROM "tb_account" ORDER BY "id" DESC
|
||||
```
|
||||
|
||||
Firebird 下执行的代码如下:
|
||||
```sql
|
||||
SELECT * FROM "tb_account" ORDER BY "id" DESC ROWS 20 TO 30
|
||||
```
|
||||
|
||||
|
||||
169
docs/zh/table.md
Normal file
169
docs/zh/table.md
Normal file
@ -0,0 +1,169 @@
|
||||
# Entity 的主键配置
|
||||
|
||||
在 Entity 类中,Mybatis-Flex 是使用 `@Id` 注解来标识主键的,如下代码所示:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
// id 为自增主键
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Long id;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
|
||||
`@Id` 注解的内容如下:
|
||||
|
||||
```java
|
||||
public @interface Id {
|
||||
|
||||
/**
|
||||
* ID 生成策略,默认为 none
|
||||
*
|
||||
* @return 生成策略
|
||||
*/
|
||||
KeyType keyType() default KeyType.None;
|
||||
|
||||
/**
|
||||
* 若 keyType 类型是 sequence, value 则代表的是
|
||||
* sequence 序列的 sql 内容
|
||||
* 例如:select SEQ_USER_ID.nextval as id from dual
|
||||
*
|
||||
* 若 keyType 是 Generator,value 则代表的是使用的那个 keyGenerator 的名称
|
||||
*
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
|
||||
/**
|
||||
* sequence 序列执行顺序
|
||||
* 是在 entity 数据插入之前执行,还是之后执行,之后执行的一般是数据主动生成的 id
|
||||
*
|
||||
* @return 执行之前还是之后
|
||||
*/
|
||||
boolean before() default true;
|
||||
}
|
||||
```
|
||||
|
||||
keyType 为主键的生成方式,KeyType 有 4 种类型:
|
||||
|
||||
```java
|
||||
public enum KeyType {
|
||||
|
||||
/**
|
||||
* 自增的方式
|
||||
*/
|
||||
Auto,
|
||||
|
||||
/**
|
||||
* 通过执行数据库 sql 生成
|
||||
* 例如:select SEQ_USER_ID.nextval as id from dual
|
||||
*/
|
||||
Sequence,
|
||||
|
||||
/**
|
||||
* 通过 IKeyGenerator 生成器生成
|
||||
*/
|
||||
Generator,
|
||||
|
||||
/**
|
||||
* 其他方式,比如说在代码层用户手动设置
|
||||
*/
|
||||
None,
|
||||
}
|
||||
```
|
||||
|
||||
## 多主键、复合主键
|
||||
|
||||
Mybatis-Flex 多主键就是在 Entity 类里有多个 `@Id` 注解标识而已,比如:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Auto)
|
||||
private Long id;
|
||||
|
||||
@Id(keyType=KeyType.Generator, value="uuid")
|
||||
private String otherId;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
当我们保存数据的时候,Account 的 id 主键为自增,而 otherId 主键则通过 uuid 生成。
|
||||
|
||||
## 主键生成器
|
||||
|
||||
第 1 步:编写一个类,实现 `IKeyGenerator` 接口,例如:
|
||||
|
||||
```java
|
||||
public class UUIDKeyGenerator implements IKeyGenerator {
|
||||
|
||||
@Override
|
||||
public Object generate(Object entity, String keyColumn) {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
第 2 步:注册 UUIDKeyGenerator
|
||||
|
||||
```java
|
||||
KeyGeneratorFactory.register("myUUID", new UUIDKeyGenerator());
|
||||
```
|
||||
|
||||
第 3 步:在 Entity 里使用 "myUUID" 生成器:
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Generator, value="myUUID")
|
||||
private String otherId;
|
||||
|
||||
//getter setter
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 使用序列 Sequence 生成
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id(keyType=KeyType.Sequence, value="select SEQ_USER_ID.nextval as id from dual")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## 全局配置
|
||||
|
||||
一般的项目中,通常是许多的 Entity 使用同一个数据库,同时使用一种主键生成方式,比如说都使用 自增,
|
||||
或者都使用通过序列(Sequence)生成,此时,我们是没有必要为每个 Entity 单独配置一样内容的。
|
||||
|
||||
Mybatis-Flex 提供了一种全局配置的方式,代码如下:
|
||||
|
||||
```java
|
||||
FlexGlobalConfig.KeyConfig keyConfig = new FlexGlobalConfig.KeyConfig();
|
||||
keyConfig.setKeyType(KeyType.Sequence);
|
||||
keyConfig.setValue("select SEQ_USER_ID.nextval as id from dual")
|
||||
keyConfig.setBefore(true);
|
||||
|
||||
FlexGlobalConfig.getDefaultConfig().setKeyConfig(keyConfig);
|
||||
```
|
||||
|
||||
此时,Entity 类 Account.java 只需要如下配置即可。
|
||||
|
||||
```java
|
||||
@Table("tb_account")
|
||||
public class Account {
|
||||
|
||||
@Id()
|
||||
private Long id;
|
||||
|
||||
}
|
||||
```
|
||||
1
docs/zh/what-is-mybatisflex.md
Normal file
1
docs/zh/what-is-mybatisflex.md
Normal file
@ -0,0 +1 @@
|
||||
# Mybatis-Flex 是什么
|
||||
Loading…
x
Reference in New Issue
Block a user