首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
拉勾
V2EX  ›  Java

使 Mybatis 开发变得更加轻松的增强工具 — Ourbatis

  •  
  •   iamniconico · 148 天前 · 3674 次点击
    这是一个创建于 148 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一、Mybatis 的不足之处

    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,在开发过程中,产品忽然提了一个新的需求,项目经理根据这个需求在某张表中增加或变动了一个字段,这时,我猜你的操作是这样:

    • 1、找到对应表的 XML
    • 2、将该 XML 中自定义的一段标签复制出来,保存在本地
    • 3、使用Mybatis Generator重新生成该表的 XML
    • 4、将之覆盖当前的 XML
    • 5、将自定义的一段标签再粘贴进新的 XML 中

    在这个过程中,如果我们在第 2 步时漏复制了一段标签,等整个操作完成之后,又别是一番滋味在心头~

    问题三:编写 XML 困难

    假如肝不错,问题二也是小 CASE,那么问题又来了,我们如何在繁长的 XML 中去编写和修改我们的 XML 呢。

    当我们打开要编辑的 XML,映入眼帘的就是 1000 多行的 XML,其中 900 行都是通用的增删改查操作,要新增一个标签,我们需要拉至文件底部编写新的数据操作,要更新一个标签,我们需要通过Ctrl + F寻找目标标签再进行修改。

    如何避免这些问题呢?

    如何让 Mybatis 增强通用性又不失灵活呢?

    二、使用 Ourbatis 辅助 Mybatis

    Ourbatis 是一款 Mybatis 开发增强工具,小巧简洁,项目地址:

    特性:

    • 1、简洁方便,可以让 Mybatis 无 XML 化开发。
    • 2、优雅解耦,通用和自定义的 SQL 标签完全隔离,让维护更加轻松。
    • 3、无侵入性,Mybatis 和 Ourbatis 可同时使用,配置简洁。
    • 4、灵活可控,通用模板可自定义及扩展。
    • 5、部署快捷,只需要一个依赖,两个配置,即可直接运行。
    • 6、多数据源,在多数据源环境下也可以照常使用。

    关于 Ourbatis 使用的一个小 Demo

    环境:

    • Spring Boot 2.0.5.RELEASE
    • Ourbatis 1.0.5
    • JAVA 8
    • Mysql

    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 自定义方法

    在很多场景中,我们使用以上的自带的通用方法远远不能满足我们的需求,我们往往需要额外扩展新的 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 流程图

    当服务启动的时候,Ourbatis 首先会扫描ourbatis.domain-locations配置包下的所有实体类,将之映射为与之对应的表结构数据: ourbatis Mapping

    然后通过ourbatis.xml的渲染,生成一个又一个的 XML 文件,最后将之重新 Build 到 Mybatis 容器中!

    整个过程分为两个核心点:

    • 1、映射实体类为元数据
    • 2、使用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:foreach 对元数据中的列表进行循环渲染
    • ourbatis:ref 引入外界文件内容

    这是 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

    53 回复  |  直到 2018-10-24 18:40:14 +08:00
        1
    xiaoxinshiwo   148 天前
    题主是没用过 tk.mybatis 吗?
    <dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper</artifactId>
    <version>3.4.2</version>
    </dependency>
        2
    iamniconico   148 天前
    @xiaoxinshiwo 没有,所以就自己写了一个
        3
    gejun123456   148 天前
    Mybatis Generator 可以不覆盖你自定义写的 xml 的,只要 xml 中一开始生成 @Mbg generated 这些注释

    加了字段后 Mybatis generator 重新生成下就解决了 不过 mybatis generator 要写 xml 配置麻烦点

    另外有个方便的 Intellij 插件 https://github.com/gejun123456/MyBatisCodeHelper-Pro 可以试试

    可以生成很多单表操作的 sql
        4
    xiaoxinshiwo   148 天前
    @iamniconico #2 嗯,给你点个赞
        5
    iamniconico   148 天前 via Android
    @gejun123456 不错,之前我也写过代码生成的工具,用了一段时间始终感觉自定义和通用的标签放在一起不好维护哈哈哈
        6
    anyele   148 天前 via Android
    和 mybatis plus 比,优势在哪
        7
    iamniconico   148 天前
    @anyele
    mybatis plus 是前辈所写的一款很优秀的 mybatis 增强工具,具体实现我还没有真正的拜读过,而 ourbatis 是我在使用 Mybatis 的过程中突发奇想(何不定制一个通用的 xml 模板,使之代替重复的标签定义?)下诞生的一款轻量级增强工具,前辈们项目的日积月累的成熟想必 ourbatis 是比不上的,但是 ourbatis 足够的灵活,因为它将通用的模板开放出入口去任由开发者编辑、修改,无论在扩展通用方法还是扩展标签方面都是非常方便的,这里就不过多阐述,ourbatis 可以实现 mybatis plus 一样的功能,但是更轻,没有集成一些常用的工具插件,希望能和 mybatis plus 一起帮助大家,使开发更方便快捷!
        8
    mdluo   148 天前 via iPhone   ♥ 3
        9
    bsg1992   148 天前   ♥ 2
    这种把 sql 写在 xml 里的框架你们为啥用的乐此不疲呢。实在理解不了啊
        10
    iamniconico   148 天前
    @bsg1992 因为不想把 sql 写在 Java 文件里呀
        11
    enaxm   148 天前
    @bsg1992 承认吧,xml(之前)是业界主流

    ajax 全称是啥来着?
        12
    nocrush   148 天前
    那么问题来了 mybatis plus 和 tk mybatis 还有其他的,更加推荐哪一个呢?
        13
    jiangnanyanyu   148 天前 via Android   ♥ 1
    点个赞,开发不易!
        14
    iamniconico   148 天前
        15
    iamniconico   148 天前
    @nocrush 都是前辈的神器,哪个好用用哪个
        16
    Zerah   148 天前   ♥ 1
    挺不错的,加油。
        17
    hdonghong   148 天前
    厉害!继续用 mybatis plus
        18
    iamniconico   148 天前
    @Zerah 谢谢
        19
    iamniconico   148 天前
    @hdonghong 有时间可以体验一下 ourbatis 哦: https://github.com/ainilili/ourbatis-simple
        20
    aristotll   148 天前
    提了个 issue 被 github 吃了....
        21
    iamniconico   148 天前 via Android
    @aristotll 哈哈,gay 还没修好
        22
    KingEngine   148 天前 via Android
    可以,这很强势
        23
    gowk   147 天前 via Android
    @bsg1992 除了 Mybatis,还有别的更好的选择吗
        24
    godoway   147 天前
    @gowk 不在 xml 里面写 sql 的话,其实还有一个 jooq。
    看起来挺美好的,但用起来的感觉也就比原生 jdbc 高级一点。
        25
    xuanbg   147 天前
    从来不写 xml 的路过,我们都是用 spring boot 的注解在 mapper 里面直接写 sql。
        26
    PhpBestRubbish   147 天前
    可以
        27
    gowk   147 天前 via Android
    @godoway jooq 就是垃圾,很反感这种把 Sql 拆开硬生生的塞进 Java 里面的做法,把简单问题复杂化了,不止 Java,其它语言里面也有很多这种垃圾,用 jooq 还不如直接 jdbcTemplate 灵活清晰明了。
        28
    w10511026   147 天前
    又一个造轮子的
        29
    LemonCoo1   147 天前
    我在公司内部全部推的是 tk mybatis 搭配 springboot 开箱即食
        30
    iamniconico   147 天前
    @xuanbg 十行以上的 sql 会不会不优雅
        31
    iamniconico   147 天前
    @LemonCoo1 tk 很不错,不过现在大多数开源都支持开箱即食
    <dependency>
    <groupId>com.smallnico</groupId>
    <artifactId>ourbatis-spring-boot-starter</artifactId>
    <version>1.0.5</version>
    </dependency>
        32
    rockyou12   147 天前   ♥ 1
    所以为啥你们都不用 jpa …… spring data jpa 这种不好嘛……
        33
    PythonAnswer   147 天前 via iPhone
    哈哈 还有一个 oursql
        34
    sonyxperia   147 天前
    和 mybatis-plus 有什么区别嘛
        35
    iamniconico   147 天前
    @sonyxperia 参考 7 楼
        36
    popvlovs   147 天前   ♥ 1
    @xuanbg +1,XML 太反人类了,写注解看起来舒服很多
        37
    xuanbg   147 天前
    @iamniconico 看上去好看有什么用。。。查询效率才是关键。
        38
    iamniconico   147 天前 via Android
    @xuanbg xml 和注解不都是在服务启动的时候都绑定 mapper 了吗?查询效率有什么差别。。。。我记得官网都推荐 xml,注解功能有限
        39
    lihongjie0209   147 天前
    为什么不用 jpa?
        40
    iamniconico   147 天前
    @lihongjie0209
    首先,对于“为什么不用 jpa ?”这个问题,我要反问一下,我为什么要用 jpa ?

    然后再正视这个问题,为什么不用 jpa ?这个问题需要一个前置条件,例如在某某场景下、某某类型的项目中,为什么不用 jpa ?这样才感觉合理,就像为什么吃饭要用筷子一样合理!

    JPA 典型的代表是 Hibernate,Mybatis 没有实现 JPA 那一套,JPA 抽象了 api, 为了替代 native sql,增加了学习成本,降低了性能。复杂的查询还是只能用 native sql。

    相比 Jpa,不像 Jpa 操作那样方便,但是性能和灵活性提高了上去,它们之前没有比较的必要,就像骑自行车一样和开轿车,从 A 点到 B 点,很可能中间有个胡同可以更快的到达终点,那就选择骑自行车,可能只能走大路,那就选择轿车罢了。
        41
    woncode   147 天前 via Android
    同觉得 xml 反人类,语法繁琐,没有优雅可言,特别是用过 spring data jpa 后,mybatis+xml 使得方法和 sql 分离,看着辣眼不说,后期维护还增加困难

    什么?性能?绝大多数系统,绝大多数方法都是普通的 curd 而已,我愿意牺牲一点性能换取一点理想的优雅,有诗和远方才能过活😂
        43
    iamniconico   147 天前
    @woncode
    "绝大多数系统,绝大多数方法都是普通的 curd 而已"这句话我无法反驳,因为你说的是真道理,比较数据库只提供的增 curd 的功能,例如多表关联统计查询也不过如此~

    个人觉得,每个系统少不了要有几个超长的 sql,写在代码里的场面难以想象,并且注解在某些方面功能有限,恐怕遇到这等需求的时候还是少不了 xml 的。

    大家都觉得 xml 反人类,不如自创一个解释文本格式好了,不晓得为啥非要贬低 xml,HTML 不也是超文本的格式,不如废弃掉好了,省的辣大家眼睛。

    在 Mybatis 繁琐的 xml 基础上增加 curd 的通用操作或许可以让所谓的绝大数系统,绝大数方法不需要依赖和定义 xml 了,在你的思维角度上 ourbatis 很适合~
        44
    blackboom   147 天前
    行行行,就知道大家要讨论 JPA,毕竟作者开发一个组件给大家用是好心,当然要鼓励,加油!

    推荐再写个 OurJPA,绝对靠谱!
        45
    ryougifujino   147 天前
    想问问 Java 有没有类似 Android 里面 Room 框架的,直接在方法上的注解里写 Sql,还有对应的高亮,很方便
        46
    disagree   147 天前
    拉拉人来支持一下
    能自己开发轮子已经很厉害了
        47
    iamniconico   147 天前
    @ryougifujino 当然,spring data jpa 配合 mybatis,不带高亮
        48
    iamniconico   147 天前
    @disagree 感谢支持
        49
    iamniconico   147 天前
    @blackboom 只是看到大家在谈论为什么不用 jpa,没忍住理论了一番,各有各的特点,不贬低,也不偏向,ourbatis 内部也在用,开源出来分享一下,感谢支持!
        50
    iamniconico   147 天前
    @PythonAnswer our 系列要崛起了?
        51
    zhuawadao   146 天前
    开发不易,支持一下,楼上都什么心态
        52
    bsg1992   146 天前
    @iamniconico 我是做.Net 对 java 这种吧 sql 写在 XML 里不是很赞同(平时也写过 java 维护过公司的 java 项目)。ORM 框架就是解决对象映射到数据模型的这种问题。 如果遇到超级复杂的 SQL,啥框架也白扯还是老老实实的写 sql
        53
    iamniconico   146 天前
    @bsg1992 是的,orm 只能解决单表多表增删改查的普通逻辑,复杂的还是要写 sql,但是把 sql 写在代码里总感觉怪怪的,首先要字符串拼接,有时候 sql 太长还要换行,整段 sql 写下来,可视化不太好,而写在 xml 里就比较方便了。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   864 人在线   最高记录 4385   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 21ms · UTC 19:43 · PVG 03:43 · LAX 12:43 · JFK 15:43
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1