Mybatis 是一款优秀的及其灵活的持久层框架,通过 XML 配置并映射到 Mapper 接口为 Service 层提供基础数据操作入口。
这么优秀的框架竟然还有不足之处?
俗话说人无完人,因为 Mybatis 实在是太灵活了,灵活到每个 Mapper 接口都需要定制对应的 XML,所以就会引发一些问题。
假如一个系统中 DB 中涉及 100 张表,我们就需要写100
个 Mapper 接口,还没完,最可怕的是,我们要为这100
个 Mapper 接口定制与之对应的100
套 XML。而每个 Mapper 都必不可少的需要增删改查功能,我们就要写100
遍增删改查,作为高贵的 Java 开发工程师,这是不能容忍的,于是Mybatis Generator
诞生了,然而又会引发另一个问题!
我们使用Mybatis Generator
解决了问题一,再多的文件生成就是了,简单粗暴,貌似解决了所有的问题,Mybatis 完美了!
不要高兴的太早,在系统刚刚建立起来时,我们使用Mybatis Generator
生成了一堆 XML,在开发过程中,产品忽然提了一个新的需求,项目经理根据这个需求在某张表中增加或变动了一个字段,这时,我猜你的操作是这样:
Mybatis Generator
重新生成该表的 XML在这个过程中,如果我们在第 2 步时漏复制了一段标签,等整个操作完成之后,又别是一番滋味在心头~
假如肝不错,问题二也是小 CASE,那么问题又来了,我们如何在繁长的 XML 中去编写和修改我们的 XML 呢。
当我们打开要编辑的 XML,映入眼帘的就是 1000 多行的 XML,其中 900 行都是通用的增删改查操作,要新增一个标签,我们需要拉至文件底部编写新的数据操作,要更新一个标签,我们需要通过Ctrl + F
寻找目标标签再进行修改。
如何避免这些问题呢?
如何让 Mybatis 增强通用性又不失灵活呢?
Ourbatis 是一款 Mybatis 开发增强工具,小巧简洁,项目地址:
特性:
环境:
以Spring Boot 2.0.5.RELEASE
版本为例,在可以正常使用 Mybatis 的项目中,pom.xml
添加如下依赖:
<dependency>
<groupId>com.smallnico</groupId>
<artifactId>ourbatis-spring-boot-starter</artifactId>
<version>1.0.5</version>
</dependency>
在配置文件中增加一下配置:
ourbatis.domain-locations=实体类所在包名
接下来,Mapper 接口只需要继承SimpleMapper
即可:
import org.nico.ourbatis.domain.User;
public interface UserMapper extends SimpleMapper<User, Integer>{
}
至此,一个使用 Ourbatis 的简单应用已经部署起来了,之后,你就可以使用一些 Ourbatis 默认的通用操作方法:
public T selectById(K key);
public T selectEntity(T condition);
public List<T> selectList(T condition);
public long selectCount(Object condition);
public List<T> selectPage(Page<Object> page);
default PageResult<T> selectPageResult(Page<Object> page){
long total = selectCount(page.getEntity());
List<T> results = null;
if(total > 0) {
results = selectPage(page);
}
return new PageResult<>(total, results);
}
public K selectId(T condition);
public List<K> selectIds(T condition);
public int insert(T entity);
public int insertSelective(T entity);
public int insertBatch(List<T> list);
public int update(T entity);
public int updateSelective(T entity);
public int updateBatch(List<T> list);
public int delete(T condition);
public int deleteById(K key);
public int deleteBatch(List<K> list);
在很多场景中,我们使用以上的自带的通用方法远远不能满足我们的需求,我们往往需要额外扩展新的 Mapper 方法、XML 标签,我们使用了 Ourbatis 之后该如何实现呢?
首先看一下我们的需求,在上述 Demo 中,我们在 UserMapper 中增加一个方法selectNameById
:
import org.nico.ourbatis.domain.User;
public interface UserMapper extends SimpleMapper<User, Integer>{
public String selectNameById(Integer userId);
}
和 Mybatis 一样,需要在resources
资源目录下新建一个文件夹ourbatis-mappers
,然后在其中新建一个 XML 文件,命名规则为:
DomainClassSimpleName + Mapper.xml
其中DomainClassSimpleName
就是我们实体类的类名,这里是为User
,那么新建的 XML 名为UserMapper.xml
。
src/main/resources
- ourbatis-mappers
- UserMapper.xml
之后,打开UserMapper.xml
,开始编写 Mapper 中selectNameById
方法对应的标签:
<select id="selectNameById" resultType="java.lang.String">
select name from user where id = #{userId}
</select>
注意,整个文件中只需要写标签就行了,其他的什么都不需要,这是为什么呢?深入之后你就会明白,这里先不多说!
接下来,就没有接下来了,可以直接使用selectNameById
方法了。
当服务启动的时候,Ourbatis 首先会扫描ourbatis.domain-locations
配置包下的所有实体类,将之映射为与之对应的表结构数据:
然后通过ourbatis.xml
的渲染,生成一个又一个的 XML 文件,最后将之重新 Build 到 Mybatis 容器中!
整个过程分为两个核心点:
ourbatis.xml
渲染元数据为 XML 文件我会一一介绍之~
在映射时,我们要根据自己数据库字段命名的风格去调整映射规则,就需要在第 1 个核心点中去做处理,Ourbatis 使用包装器来完成:
public interface Wrapper<T> {
public String wrapping(T value);
}
对于需要映射的字段,如表名和表字段名,它们都将会经过一个包装器链条的处理之后再投入到ourbatis.xml
中做渲染,这样就使得我们可以自定义包装器出更换映射的字段格式,具体方式可以参考官方 Wiki:Wrapper 包装器
ourbatis.xml
渲染元数据为 XML 文件而在于第 2 个核心点中,Ourbatis 通过自定义标签做模板渲染,我们可以先看一下官方默认的ourbatis.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="@{mapperClassName}">
<resultMap id="BaseResultMap" type="@{domainClassName}">
<ourbatis:foreach list="primaryColumns" var="elem">
<id column="@{elem.jdbcName}" property="@{elem.javaName}" />
</ourbatis:foreach>
<ourbatis:foreach list="normalColumns" var="elem">
<result column="@{elem.jdbcName}" property="@{elem.javaName}" />
</ourbatis:foreach>
</resultMap>
<sql id="Base_Column_List">
<ourbatis:foreach list="allColumns" var="elem"
split=",">
`@{elem.jdbcName}`
</ourbatis:foreach>
</sql>
<select id="selectById" parameterType="java.lang.Object"
resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from @{tableName}
where 1 = 1
<ourbatis:foreach list="primaryColumns" var="elem">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</ourbatis:foreach>
</select>
<select id="selectEntity" parameterType="@{domainClassName}"
resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from @{tableName}
where 1 = 1
<ourbatis:foreach list="allColumns" var="elem">
<if test="@{elem.javaName} != null">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</if>
</ourbatis:foreach>
limit 1
</select>
<select id="selectCount" parameterType="@{domainClassName}"
resultType="long">
select count(0)
from @{tableName}
where 1 = 1
<ourbatis:foreach list="allColumns" var="elem">
<if test="@{elem.javaName} != null">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</if>
</ourbatis:foreach>
limit 1
</select>
<select id="selectPage"
parameterType="org.nico.ourbatis.entity.Page"
resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from @{tableName}
where 1 = 1
<if test="entity != null">
<ourbatis:foreach list="allColumns" var="elem">
<if test="entity.@{elem.javaName} != null">
and `@{elem.jdbcName}` = #{entity.@{elem.javaName}}
</if>
</ourbatis:foreach>
</if>
<if test="orderBy != null">
order by ${orderBy}
</if>
<if test="start != null and end != null">
limit ${start},${end}
</if>
</select>
<select id="selectList" parameterType="@{domainClassName}"
resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from @{tableName}
where 1 = 1
<ourbatis:foreach list="allColumns" var="elem">
<if test="@{elem.javaName} != null">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</if>
</ourbatis:foreach>
</select>
<select id="selectId" parameterType="@{domainClassName}"
resultType="java.lang.Object">
select
<ourbatis:foreach list="primaryColumns" var="elem"
split=",">
`@{elem.jdbcName}`
</ourbatis:foreach>
from @{tableName}
where 1 = 1
<ourbatis:foreach list="allColumns" var="elem">
<if test="@{elem.javaName} != null">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</if>
</ourbatis:foreach>
limit 1
</select>
<select id="selectIds" parameterType="@{domainClassName}"
resultType="java.lang.Object">
select
<ourbatis:foreach list="primaryColumns" var="elem"
split=",">
`@{elem.jdbcName}`
</ourbatis:foreach>
from @{tableName}
where 1 = 1
<ourbatis:foreach list="normalColumns" var="elem">
<if test="@{elem.javaName} != null">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</if>
</ourbatis:foreach>
</select>
<delete id="deleteById" parameterType="java.lang.Object">
delete
from @{tableName}
where 1=1
<ourbatis:foreach list="primaryColumns" var="elem">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</ourbatis:foreach>
</delete>
<insert id="insert" keyProperty="@{primaryColumns.0.jdbcName}"
useGeneratedKeys="true" parameterType="@{domainClassName}">
insert into @{tableName}
(
<include refid="Base_Column_List" />
)
values (
<ourbatis:foreach list="allColumns" var="elem"
split=",">
#{@{elem.javaName}}
</ourbatis:foreach>
)
</insert>
<insert id="insertSelective"
keyProperty="@{primaryColumns.0.jdbcName}" useGeneratedKeys="true"
parameterType="@{domainClassName}">
insert into @{tableName}
(
<ourbatis:foreach list="primaryColumns" var="elem"
split=",">
`@{elem.jdbcName}`
</ourbatis:foreach>
<ourbatis:foreach list="normalColumns" var="elem">
<if test="@{elem.javaName} != null">
,`@{elem.jdbcName}`
</if>
</ourbatis:foreach>
)
values (
<ourbatis:foreach list="primaryColumns" var="elem">
#{@{elem.javaName}}
</ourbatis:foreach>
<ourbatis:foreach list="normalColumns" var="elem">
<if test="@{elem.javaName} != null">
, #{@{elem.javaName}}
</if>
</ourbatis:foreach>
)
</insert>
<insert id="insertBatch"
keyProperty="@{primaryColumns.0.jdbcName}" useGeneratedKeys="true"
parameterType="java.util.List">
insert into @{tableName}
(
<include refid="Base_Column_List" />
)
values
<foreach collection="list" index="index" item="item"
separator=",">
(
<ourbatis:foreach list="allColumns" var="elem"
split=",">
#{item.@{elem.javaName}}
</ourbatis:foreach>
)
</foreach>
</insert>
<update id="update" parameterType="@{domainClassName}">
update @{tableName}
<set>
<ourbatis:foreach list="normalColumns" var="elem"
split=",">
`@{elem.jdbcName}` = #{@{elem.javaName}}
</ourbatis:foreach>
</set>
where 1=1
<ourbatis:foreach list="primaryColumns" var="elem">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</ourbatis:foreach>
</update>
<update id="updateSelective" parameterType="@{domainClassName}">
update @{tableName}
<set>
<ourbatis:foreach list="primaryColumns" var="elem"
split=",">
`@{elem.jdbcName}` = #{@{elem.javaName}}
</ourbatis:foreach>
<ourbatis:foreach list="normalColumns" var="elem">
<if test="@{elem.javaName} != null">
,`@{elem.jdbcName}` = #{@{elem.javaName}}
</if>
</ourbatis:foreach>
</set>
where 1=1
<ourbatis:foreach list="primaryColumns" var="elem">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</ourbatis:foreach>
</update>
<update id="updateBatch" parameterType="java.util.List">
<foreach collection="list" index="index" item="item"
separator=";">
update @{tableName}
<set>
<ourbatis:foreach list="normalColumns" var="elem"
split=",">
`@{elem.jdbcName}` = #{item.@{elem.javaName}}
</ourbatis:foreach>
</set>
where 1=1
<ourbatis:foreach list="primaryColumns" var="elem">
and `@{elem.jdbcName}` = #{item.@{elem.javaName}}
</ourbatis:foreach>
</foreach>
</update>
<delete id="deleteBatch" parameterType="java.util.List">
delete from @{tableName} where @{primaryColumns.0.jdbcName} in
<foreach close=")" collection="list" index="index" item="item"
open="(" separator=",">
#{item}
</foreach>
</delete>
<delete id="delete" parameterType="@{domainClassName}">
delete from @{tableName} where 1 = 1
<ourbatis:foreach list="allColumns" var="elem">
<if test="@{elem.javaName} != null">
and `@{elem.jdbcName}` = #{@{elem.javaName}}
</if>
</ourbatis:foreach>
</delete>
<ourbatis:ref path="classpath:ourbatis-mappers/@{domainSimpleClassName}Mapper.xml" />
</mapper>
可以看出来,ourbatis.xml
内容类似于原生的 Mybatis 的 XML,不同的是,有两个陌生的标签:
这是 Ourbatis 中独有的标签,Ourbatis 也提供着对应的入口让我们去自定义标签:
Class: org.nico.ourbatis.Ourbatis
Field:
public static final Map<String, AssistAdapter> ASSIST_ADAPTERS = new HashMap<String, AssistAdapter>(){
private static final long serialVersionUID = 1L;
{
put("ourbatis:foreach", new ForeachAdapter());
put("ourbatis:ref", new RefAdapter());
}
};
我们可以修改org.nico.ourbatis.Ourbatis
类中的静态参数ASSIST_ADAPTERS
去删除、更新和添加自定义标签,需要实现一个标签适配器,我们可以看一下最简单的RefAdapter
适配器的实现:
public class RefAdapter extends AssistAdapter{
@Override
public String adapter(Map<String, Object> datas, NoelRender render, Document document) {
String path = render.rending(datas, document.getParameter("path"), "domainSimpleClassName");
String result = StreamUtils.convertToString(path.replaceAll("classpath:", ""));
return result == null ? "" : result.trim();
}
}
Ourbatis 中只定义了上述两个自定义标签已足够满足需求,通过foreach
标签,将元数据中的集合遍历渲染,通过ref
标签引入外界资源,也就是我们之前所说的对 Mapper 接口中方法的扩展!
<ourbatis:ref path="classpath:ourbatis-mappers/@{domainSimpleClassName}Mapper.xml" />
其中的 path 就是当前项目 classpath 路径的相对路径,而@{domainSimpleClassName}
就代表着实体类的类名,更多的系统参数可以参考 Wiki:元数据映射
通过这种模板渲染的机制,Ourbatis 是相当灵活的,我们不仅可以通过引入外部文件进行扩展,当我们需要添加或修改通用方法时,我们可以可以自定义ourbatis.xml
的内容,如何做到呢?复制一份将之放在资源目录下就可以了!
看到这里,相信大家已经知道 Ourbatis 的基本原理已经使用方式,我就再次不多说了,更多细节可以去官方 Wiki 中阅读:Ourbtis Wiki
1
xiaoxinshiwo 2018-10-22 11:09:41 +08:00
题主是没用过 tk.mybatis 吗?
<dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>3.4.2</version> </dependency> |
2
iamniconico OP @xiaoxinshiwo 没有,所以就自己写了一个
|
3
gejun123456 2018-10-22 11:26:08 +08:00
Mybatis Generator 可以不覆盖你自定义写的 xml 的,只要 xml 中一开始生成 @Mbg generated 这些注释
加了字段后 Mybatis generator 重新生成下就解决了 不过 mybatis generator 要写 xml 配置麻烦点 另外有个方便的 Intellij 插件 https://github.com/gejun123456/MyBatisCodeHelper-Pro 可以试试 可以生成很多单表操作的 sql |
4
xiaoxinshiwo 2018-10-22 11:26:45 +08:00
@iamniconico #2 嗯,给你点个赞
|
5
iamniconico OP @gejun123456 不错,之前我也写过代码生成的工具,用了一段时间始终感觉自定义和通用的标签放在一起不好维护哈哈哈
|
6
anyele 2018-10-22 12:34:46 +08:00 via Android
和 mybatis plus 比,优势在哪
|
7
iamniconico OP @anyele
mybatis plus 是前辈所写的一款很优秀的 mybatis 增强工具,具体实现我还没有真正的拜读过,而 ourbatis 是我在使用 Mybatis 的过程中突发奇想(何不定制一个通用的 xml 模板,使之代替重复的标签定义?)下诞生的一款轻量级增强工具,前辈们项目的日积月累的成熟想必 ourbatis 是比不上的,但是 ourbatis 足够的灵活,因为它将通用的模板开放出入口去任由开发者编辑、修改,无论在扩展通用方法还是扩展标签方面都是非常方便的,这里就不过多阐述,ourbatis 可以实现 mybatis plus 一样的功能,但是更轻,没有集成一些常用的工具插件,希望能和 mybatis plus 一起帮助大家,使开发更方便快捷! |
8
mdluo 2018-10-22 14:48:44 +08:00 via iPhone 3
|
9
bsg1992 2018-10-22 16:38:19 +08:00 2
这种把 sql 写在 xml 里的框架你们为啥用的乐此不疲呢。实在理解不了啊
|
10
iamniconico OP @bsg1992 因为不想把 sql 写在 Java 文件里呀
|
12
nocrush 2018-10-22 18:18:06 +08:00
那么问题来了 mybatis plus 和 tk mybatis 还有其他的,更加推荐哪一个呢?
|
13
jiangnanyanyu 2018-10-22 18:40:18 +08:00 via Android 1
点个赞,开发不易!
|
14
iamniconico OP @jiangnanyanyu 谢谢
|
15
iamniconico OP @nocrush 都是前辈的神器,哪个好用用哪个
|
16
Zerah 2018-10-22 20:50:51 +08:00 1
挺不错的,加油。
|
17
hdonghong 2018-10-22 20:51:15 +08:00
厉害!继续用 mybatis plus
|
18
iamniconico OP @Zerah 谢谢
|
19
iamniconico OP @hdonghong 有时间可以体验一下 ourbatis 哦: https://github.com/ainilili/ourbatis-simple
|
20
aristotll 2018-10-22 21:15:06 +08:00
提了个 issue 被 github 吃了....
|
21
iamniconico OP @aristotll 哈哈,gay 还没修好
|
22
KingEngine 2018-10-23 00:48:36 +08:00 via Android
可以,这很强势
|
24
godoway 2018-10-23 08:16:27 +08:00
@gowk 不在 xml 里面写 sql 的话,其实还有一个 jooq。
看起来挺美好的,但用起来的感觉也就比原生 jdbc 高级一点。 |
25
xuanbg 2018-10-23 08:56:38 +08:00
从来不写 xml 的路过,我们都是用 spring boot 的注解在 mapper 里面直接写 sql。
|
26
PhpBestRubbish 2018-10-23 09:12:14 +08:00
可以
|
27
gowk 2018-10-23 09:27:16 +08:00 via Android
@godoway jooq 就是垃圾,很反感这种把 Sql 拆开硬生生的塞进 Java 里面的做法,把简单问题复杂化了,不止 Java,其它语言里面也有很多这种垃圾,用 jooq 还不如直接 jdbcTemplate 灵活清晰明了。
|
28
w10511026 2018-10-23 09:30:28 +08:00
又一个造轮子的
|
29
LemonCoo1 2018-10-23 09:42:14 +08:00
我在公司内部全部推的是 tk mybatis 搭配 springboot 开箱即食
|
30
iamniconico OP @xuanbg 十行以上的 sql 会不会不优雅
|
31
iamniconico OP @LemonCoo1 tk 很不错,不过现在大多数开源都支持开箱即食
<dependency> <groupId>com.smallnico</groupId> <artifactId>ourbatis-spring-boot-starter</artifactId> <version>1.0.5</version> </dependency> |
32
rockyou12 2018-10-23 09:50:19 +08:00 1
所以为啥你们都不用 jpa …… spring data jpa 这种不好嘛……
|
33
PythonAnswer 2018-10-23 09:52:28 +08:00 via iPhone
哈哈 还有一个 oursql
|
34
sonyxperia 2018-10-23 10:06:39 +08:00
和 mybatis-plus 有什么区别嘛
|
35
iamniconico OP @sonyxperia 参考 7 楼
|
37
xuanbg 2018-10-23 12:22:00 +08:00
@iamniconico 看上去好看有什么用。。。查询效率才是关键。
|
38
iamniconico OP @xuanbg xml 和注解不都是在服务启动的时候都绑定 mapper 了吗?查询效率有什么差别。。。。我记得官网都推荐 xml,注解功能有限
|
39
lihongjie0209 2018-10-23 12:30:17 +08:00
为什么不用 jpa?
|
40
iamniconico OP @lihongjie0209
首先,对于“为什么不用 jpa ?”这个问题,我要反问一下,我为什么要用 jpa ? 然后再正视这个问题,为什么不用 jpa ?这个问题需要一个前置条件,例如在某某场景下、某某类型的项目中,为什么不用 jpa ?这样才感觉合理,就像为什么吃饭要用筷子一样合理! JPA 典型的代表是 Hibernate,Mybatis 没有实现 JPA 那一套,JPA 抽象了 api, 为了替代 native sql,增加了学习成本,降低了性能。复杂的查询还是只能用 native sql。 相比 Jpa,不像 Jpa 操作那样方便,但是性能和灵活性提高了上去,它们之前没有比较的必要,就像骑自行车一样和开轿车,从 A 点到 B 点,很可能中间有个胡同可以更快的到达终点,那就选择骑自行车,可能只能走大路,那就选择轿车罢了。 |
41
woncode 2018-10-23 13:09:37 +08:00 via Android
同觉得 xml 反人类,语法繁琐,没有优雅可言,特别是用过 spring data jpa 后,mybatis+xml 使得方法和 sql 分离,看着辣眼不说,后期维护还增加困难
什么?性能?绝大多数系统,绝大多数方法都是普通的 curd 而已,我愿意牺牲一点性能换取一点理想的优雅,有诗和远方才能过活😂 |
43
iamniconico OP @woncode
"绝大多数系统,绝大多数方法都是普通的 curd 而已"这句话我无法反驳,因为你说的是真道理,比较数据库只提供的增 curd 的功能,例如多表关联统计查询也不过如此~ 个人觉得,每个系统少不了要有几个超长的 sql,写在代码里的场面难以想象,并且注解在某些方面功能有限,恐怕遇到这等需求的时候还是少不了 xml 的。 大家都觉得 xml 反人类,不如自创一个解释文本格式好了,不晓得为啥非要贬低 xml,HTML 不也是超文本的格式,不如废弃掉好了,省的辣大家眼睛。 在 Mybatis 繁琐的 xml 基础上增加 curd 的通用操作或许可以让所谓的绝大数系统,绝大数方法不需要依赖和定义 xml 了,在你的思维角度上 ourbatis 很适合~ |
44
blackboom 2018-10-23 13:51:46 +08:00
行行行,就知道大家要讨论 JPA,毕竟作者开发一个组件给大家用是好心,当然要鼓励,加油!
推荐再写个 OurJPA,绝对靠谱! |
45
ryougifujino 2018-10-23 13:58:44 +08:00
想问问 Java 有没有类似 Android 里面 Room 框架的,直接在方法上的注解里写 Sql,还有对应的高亮,很方便
|
46
disagree 2018-10-23 14:01:59 +08:00
拉拉人来支持一下
能自己开发轮子已经很厉害了 |
47
iamniconico OP @ryougifujino 当然,spring data jpa 配合 mybatis,不带高亮
|
48
iamniconico OP @disagree 感谢支持
|
49
iamniconico OP @blackboom 只是看到大家在谈论为什么不用 jpa,没忍住理论了一番,各有各的特点,不贬低,也不偏向,ourbatis 内部也在用,开源出来分享一下,感谢支持!
|
50
iamniconico OP @PythonAnswer our 系列要崛起了?
|
51
zhuawadao 2018-10-24 16:00:44 +08:00
开发不易,支持一下,楼上都什么心态
|
52
bsg1992 2018-10-24 17:19:41 +08:00
@iamniconico 我是做.Net 对 java 这种吧 sql 写在 XML 里不是很赞同(平时也写过 java 维护过公司的 java 项目)。ORM 框架就是解决对象映射到数据模型的这种问题。 如果遇到超级复杂的 SQL,啥框架也白扯还是老老实实的写 sql
|
53
iamniconico OP @bsg1992 是的,orm 只能解决单表多表增删改查的普通逻辑,复杂的还是要写 sql,但是把 sql 写在代码里总感觉怪怪的,首先要字符串拼接,有时候 sql 太长还要换行,整段 sql 写下来,可视化不太好,而写在 xml 里就比较方便了。
|