返回主键
1.XML方式
<insert id="bb" parameterType="XX.XX.XXEntity包" useGeneratedKeys="true" keyProperty="id">
这里是insert语句
</insert>
2.注解方式,要在接口方法上加两个注解,一个是insert,一个是selectKey
@Insert("这里是insert语句")
@SelectKey(statement = "SELECT last_insert_id() as id", keyProperty = "id", before = false, resultType = String.class, statementType = StatementType.STATEMENT)
//entity里要有id这个属性并且有getset方法,上面的resultType要注意,你的entity里的id是什么属性,就写什么,我的id是String,所以我写String.class,如果你的是int,那么请写Integer.class
public int insert(实体类 entity);
循环
本文展示了这样一个业务:根据多个ID删除多条数据
public Integer 方法名AA(@Param("bb") String[] ids);
1.Mybatis接口方式,接口方式的循环通常很好些,因为@param可以指定名字
<delete id="方法名AA" resultMap="如果是查询记得写返回值类型">
delete from 表 where id in
//如果是批量插入记得删掉open和close属性
<foreach collection="bb" item="item" index="index" open="("
separator="," close=")">
#{item}
</foreach>
</delete>
2.Mybatis映射方式,如果使用映射方式,bb如果不放到map中,那么mybatis会把他的名字变成list,所以如下写,不再用item属性了
<delete id="方法名AA" resultMap="如果是查询记得写返回值类型">
delete from 表 where id in
//如果是批量插入记得删掉open和close属性
<foreach collection="list" index="index" item="aaa" open="("
separator="," close=")">
#{list[${index}]}
</foreach>
</delete>
注: 当mybatis以映射方式循环的时候,你们会发现循环语句中有个item=“aaa”,虽然我下面没有用到这个,但是item必须写,哪怕是item=“bbb”,item=“ccc”,必须要写,否则mybatis报错
加前缀后缀覆盖
下面的例子展示了如果传递用户名称,则将用户名称userName和年龄userAge作为条件进行或查询,但是由于前面有一个逻辑删除表示is_deleted = 0
,这导致如果不进行特殊处理,后面name+age无法在一个括号里,但是如果在一个括号里(所以使用prefix+suffix
),并且name前面的OR要消失,所以使用prefixOverrides
select * from 表
where
is_deleted = 0
<trim prefix="(" suffix=")" prefixOverrides="OR">
<if test="userName=null and userName!=''">
OR t1.`name` = #{userName}
</if>
<if test="userAge=null and userAge!=''">
OR t1.`age` = #{userAge}
</if>
</trim>
递归
下面的示例展示了获取性别是’男’的人下面所有的子孙,新建一个entity,如下
public class User{
private String name;
public List<User> children;
// 示例省略get set
}
dao接口(mapper)中有个方法,这个方法获取递归结构
public interface UserMapper{
List<User> getRecursionTree(@Param("parentId") String parentId, @Param("sex") String sex);
}
sql.xml写法如下
<resultMap id="RecursionBaseResultMap" type="User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="parent_id" property="parentId"/>
<collection column="id" property="children" select="getChildren">
<!--
column=id表示表中id字段作为下一个层级的parentId,
也就是说这个id,会自动作为内层sql getChildren的
#{pid},无论内层sql的parent_id = #{这里写什么都可以},
因为内层sql只有一个值,所以会自动将id匹配到内层sql的#{pid}
property=children对应User类的children字段
select=getChildren对应下面的内层sql的id字段
-->
</collection>
</resultMap>
<!-- 外层sql -->
<!-- 注意resultMap和最上边的对应上 -->
<select id="getRecursionTree" resultMap="RecursionBaseResultMap">
select *
from scheme_scope
where parent_id = #{pid}
and sex= #{sex}
</select>
<!-- 内层sql -->
<!-- 注意resultMap和最上边的对应上 -->
<select id="getChildren" resultMap="RecursionBaseResultMap">
select * from user
where parent_id = #{pid}
</select>
Sql入参为Map
入参为map一般情况都是JSON_SET业务场景,不然用map不是智力有问题吗
Dao接口如下
void updateWuhan(@Param("wuhanMap") Map<String, String> wuhanMap);
SQL XML
<update id="updateWuhan">
UPDATE 表
SET 列1=JSON_SET(列1,
<foreach collection="wuhanMap" index="key" item="value"
separator=",">
CONCAT("$.",#{key}),#{value}
</foreach>
)
</update>
Sql返回值为Map
这个功能通常用于批量查询,主要操作就是@MapKey注解
Dao接口如下
@MapKey("userId")
Map<String, UserEntity> findUserMap(@Param("userIds") List<Integer> userIds);
XML的sql正常写就行,没什么特殊的,如下
<select id="findUserMap" resultType="xxx.xxx.UserEntity">
SELECT * FROM user WHERE user_id IN
<if test="userIds!= null and userIds.size() > 0">
<foreach collection="userIds" item="userId" open="(" separator="," close=")">
#{userId}
</foreach>
</if>
</select>
Sql入参为枚举
注:这个操作需要TypeHandler,后文有自定义TypeHandler
假设有个性别枚举类,如下
public enum UserSex {
WOMEN,
MAN;
}
恰好数据库中sex字段0表示女,1表示男,如果要查询所有性别是男的数据,则
dao层接口如下
public interface UserMapper{
List<User> findBySex(@Param("sex") UserSex sex);
}
sql.xml如下
<select id="findBySex" resultType="xxx.xxx.UserEntity">
select * from `user`
where sex = #{sex,javaType=com.xxx.UserSex,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}
</select>
NOTE:根据枚举名称取值的解析器是org.apache.ibatis.type.EnumTypeHandler
Sql返回值为枚举
实现这个其实就是自定义TypeHandler(我个人觉得叫TypeResolver更好理解一些)
上个例子已经说过,枚举其实就是使用的mybatis自己实现的TypeHandler,具体实现是EnumTypeHandler,下面的例子阐述我们自己实现一个TypeHandler,假设我的数据库中是下面这个样子的,如图
当我查询的时候,我希望返回如下数据结构:
public class Order {
private String id;
private String orderNum;
private List<OrderDetail> details;// 注意此处
}
public class OrderDetail{
private String key;
private String value;
}
很明显可以看到order_detail字段,应该对应2个OrderDetail实例,那么如何把{"name":"皮冻","type":"英短"}
这个JSON字符串变成2个OrderDetail实例呢?需要两步
1.创建一个解析器(TypeHandler)
2.在SQL XML中指定order_detail字段使用该解析器
自定义解析器(TypeHandler)
public class SwtTypeHandler implements TypeHandler<List<OrderDetail>> {
@Override
public void setParameter(PreparedStatement ps, int i, List<OrderDetail> parameter, JdbcType jdbcType) throws SQLException {
// NOOP
// 此处可能查询带参数的时候会使用???
// 因为源码没有注释,而且我自己也没有测试此处,以后需要的时候再补此处吧
}
@Override
public List<OrderDetail> getResult(ResultSet rs, String columnName) throws SQLException {
String updateText = rs.getString(columnName);
return parseDetails(updateText);
}
@Override
public List<OrderDetail> getResult(ResultSet rs, int columnIndex) throws SQLException {
String updateText = rs.getString(columnIndex);
return parseDetails(updateText);
}
@Override
public List<OrderDetail> getResult(CallableStatement cs, int columnIndex) throws SQLException {
String updateText = cs.getString(columnIndex);
return parseDetails(updateText);
}
public List<OrderDetail> parseDetails(String updateText) {
if (StringUtils.hasLength(updateText)) {
List<OrderDetail> detailList= new ArrayList<>();
JSONObject jsonObject = JSON.parseObject(updateText);
for (String element : jsonObject.keySet()) {
OrderDetail detail = new OrderDetail();
detail.setKey(element);
detail.setValue(jsonObject.getString(element));
detailList.add(detail);
}
return detailList;
}
return new ArrayList<>();
}
}
SQL XML
<resultMap id="Test666" type="com.xx.xx.Order">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="order_num" jdbcType="VARCHAR" property="orderNum"/>
<result column="order_detail" <!--对应数据库的字段-->
property="details" <!--对应entity的字段-->
javaType="java.util.List" <!--entity中该字段的类型-->
<!--通过SwtTypeHandler解析器将数据库中order_detail字段的值,转换成entity中detils字段的值-->
typeHandler="com.xx.xx.SwtTypeHandler"/>
</resultMap>
<select id="随便起个名字" resultMap="Test666">
select * from `order`
</select>