目录
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
6.1:mybait封装结果集时会按照列名和属性名一一对应,如果对应不上就为null;
6.3.2:运用association标签定义对象的封装规则
8.7:mybatis的ognl表达式以及_parameter参数和_databaseId参数
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
- cache – 给定命名空间的缓存配置。
- cache-ref – 其他命名空间缓存配置的引用。
- resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
parameterMap– 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除,这里不会记录。- sql – 可被其他语句引用的可重用语句块。
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
1:insert, update 和 delete
id | 命名空间中的唯一标识符,可被用来代表这条语句。 |
parameterType | 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 |
flushCache | 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句)。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。对应原生jdbc的statement;callable为调用存储过程的; |
useGeneratedKeys | (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。 |
keyProperty | (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
keyColumn | (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
databaseId | 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
1.1获取自增主键的值
1:设置映射文件
<!--让mybatis自动的将自增的id赋值给employee的id属性 useGeneratedKeys="true" 调用的是原生jdbc的获取自增主键的方法 keyColumn,将自增主键赋值给哪个字段 --> <insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id"> insert into t_employee(name,email) VALUES(#{name},#{email}) </insert>
2:测试
/**
* 新增sql;结束后必须提交
*/
@Test
public void test02() {
//获取和数据库的一次会话;相当于getConnection();
SqlSession session = sqlSessionFactory.openSession();
try {
//使用SqlSession操作数据库,获取到dao接口的实现
EmployeeDao mapper = session.getMapper(EmployeeDao.class);
//调用方法得出结果
Employee abc = new Employee("abc", "aa@qq.com");
Integer i = mapper.insertEmployee(abc);
System.out.println("--->"+i);
System.out.println("--->"+abc.getId());
session.commit();
} finally {
//关闭连接
session.close();
}
}
1.2:获取非自增主键的值
<!--非自增主键--> <insert id="insertEmployee2" useGeneratedKeys="true" keyProperty="id"> <selectKey order="BEFORE" resultType="int" keyProperty="id"> select max(id)+1 from t_employee </selectKey> insert into t_employee(name,email) VALUES(#{name},#{email}) </insert>
selectKey标签
keyProperty | selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
keyColumn | 匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
resultType | 结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。 |
order | 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入语句内部可能有嵌入索引调用。 |
statementType | 与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。 |
2:参数传递---方法参数向sql映射语句映射
2.1:单个参数
方法: public Employee getEmployee(Integer id);
映射的sql:
<select id="getEmployee" resultType="com.wkl.bean.Employee"> select * from t_employee where id =#{id} </select>
甚至#{haha}都能取到
2.2:多个参数
方法: public Employee getEmployee2(Integer id,String name);
sql映射:
<select id="getEmployee2" resultType="com.wkl.bean.Employee"> select * from t_employee where id =#{param1} and name = #{param2} </select>
2.3:用@param指定参数(推荐)
方法: public Employee getEmployee2(@Param("id") Integer id, @Param("name") String name);
sql映射文件:
<select id="getEmployee2" resultType="com.wkl.bean.Employee"> select * from t_employee where id =#{id} and name = #{name} </select>
2.4:传入pojo(javabean)
方法名:public Employee getEmployee3(Employee ee);
sql映射:
<select id="getEmployee3" resultType="com.wkl.bean.Employee"> select * from t_employee where id =#{id} and name = #{name} </select>
2.5:传入map
2.6:传入混合参数
public Employee getEmployee4(@Param("id")Integer id,String name, Employee ee);
Integer id --->#{id}
name ---->#{param2}
Employee ee (取这里面的name)---->#{param3.name}
3:参数处理---设定参数的类型和$/#取值
1:参数也可以指定一个特殊的数据类型
<select id="getEmployee" resultType="com.wkl.bean.Employee"> select * from t_employee where id =#{id,jdbcType=numeric} </select>
resultMap、typeHandler、jdbcTypeName、expression
•实际上通常被设置的是: 可能为空的列名指定 jdbcType
•实际上通常被设置的是: 可能为空的列名指定 jdbcType
2:#{属性名}和${属性名}的区别
1:#{属性名}支持参数预编译,参数位置用?代替;参数都数预编译设置进去的,安全,不会有sql注入
<select id="getEmployee3" resultType="com.wkl.bean.Employee"> select * from t_employee where id =#{id} and name = #{name} </select>
2:${属性名}不支持参数预编译,而是直接和sql'进行拼串;不安全;但是在表名;字段名等不支持参数预编译的地方会很方便
<select id="getEmployee2" resultType="com.wkl.bean.Employee"> select * from ${tablename} where id =#{id} and name = #{name} </select>
4: 查询返回集合list
方法:
public List<Employee> getEmployeeALL();
sql映射:
<!--public List<Employee> getEmployeeALL();--> <!--resultType,如果返回集合;里面写的是返回集合的元素的类型--> <select id="getEmployeeALL" resultType="com.wkl.bean.Employee"> select * from t_employee </select>
5: 查询返回map
5.1:查询返回一个map
<!--public Map<String,Object> getEmployeeResultMap(Integer id);--> <!--resultType直接写map就行;到时候封装的时候就会将数据库字段名作为key;数据库字段值作为value--> <select id="getEmployeeResultMap" resultType="map"> select * from t_employee where id = #{id} </select>
5.2:查询返回多个map
方法:
/*必须指定那个字段作为主键;否则mybatis无法去对应*/ @MapKey("id") public Map<Integer,Employee> getEmployeeAllResultMap();
sql映射文件:
<!--public Map<Integer,Employee> getEmployeeAllResultMap();--> <select id="getEmployeeAllResultMap" resultType="com.wkl.bean.Employee"> select * from t_employee </select>
6:resultMap---自定义封装结果集
6.1:mybait封装结果集时会按照列名和属性名一一对应,如果对应不上就为null;
表:
javabean
sql映射文件:
<!--public Cat getCat(Integer id);--> <select id="getCat" resultType="com.wkl.bean.Cat"> select * from t_cat where id = #{id} </select>
结果:
6.2:自定义resultMap封装结果集
sql映射:
<!--public Cat getCat(Integer id);-->
<!--想要使用自定义的结果集;那么就将resultType换成resultMap-->
<select id="getCat" resultMap="mycat">
select * from t_cat where id = #{id}
</select>
<!--
id:唯一标识
type:指定为那个javabean封装结果集,全类名
-->
<resultMap id="mycat" type="com.wkl.bean.Cat">
<!--指定主键的对应规则
column="id" :指定那一列是主键列
property="id" :指定cat的那个属性封装id的这一列数据
-->
<id property="id" column="id"></id>
<!--
普通列;字段规则一样
-->
<result property="name" column="cname"></result>
<result property="age" column="cage"></result>
</resultMap>
结果:
6.3:封装复杂类型的对象(即对象里包含对象);
6.3.1:运用级联属性封装
javabean;
sql映射文件:
结果:
6.3.2:运用association标签定义对象的封装规则
sql映射文件
<!--public Cat getCat1(Integer id);--> <select id="getCat1" resultMap="mycat2"> select c.id as cid,c.cname,c.cage,c.person,e.id as eid,e.name,e.email from t_cat c LEFT JOIN t_employee e on c.person = e.id where c.id = #{id} </select>
<resultMap id="mycat2" type="com.wkl.bean.Cat"> <id property="id" column="cid"></id> <result property="name" column="cname"></result> <result property="age" column="cage"></result> <!--接下来的属性是一个对象,自定义这个对象的封装规则,使用association表示联合一个对象 javaType表示指定这个属性的类型 --> <association property="employee" javaType="com.wkl.bean.Employee"> <id property="id" column="eid"></id> <result property="name" column="name"></result> <result property="email" column="email"></result> </association> </resultMap>
6.4:查询对象中的封装集合-Collection
表关系:一个人有多个猫
javabean:
sql映射文件:
<!--public Employee getEmployeeCats(Integer id);--> <select id="getEmployeeCats" resultMap="mycat3"> select c.id as cid,c.cname,c.cage,c.person,e.id as eid,e.name,e.email from t_cat c LEFT JOIN t_employee e on c.person = e.id where e.id = #{id} </select> <resultMap id="mycat3" type="com.wkl.bean.Employee"> <id property="id" column="eid"></id> <result property="name" column="name"></result> <result property="email" column="email"></result> <!--collection定义集合元素的封装 property:指定那个属性是几个元素 ofType:指定几个元素里面的封装规则 --> <collection property="cats" ofType="com.wkl.bean.Cat"> <id property="id" column="cid"></id> <result property="name" column="cname"></result> <result property="age" column="cage"></result> </collection> </resultMap>
结果:
7:分步查询和延迟加载(不推荐)
7.1:分部查询
目的:就是将复杂的链接查询变成多个简单的查询;然后用前一个的结果集给第二个查询做参数
7.1.1:association-分段查询
说明:一个猫有一个主人;
sql映射:
这是另一个方法;专门利用人员id查询人员信息
<!--public Employee getEmployee(Integer id);--> <select id="getEmployee" resultType="com.wkl.bean.Employee"> select * from t_employee where id =#{id} </select>
查询猫的信息;因为猫拥有一个主人,所以在association中利用分部查询进行主人的信息; <!--public Cat getCat2(Integer id);--> <select id="getCat2" resultMap="myassciation"> select * from t_cat where id = #{id} </select> <resultMap id="myassciation" type="com.wkl.bean.Cat"> <id property="id" column="id"></id> <result property="name" column="cname"></result> <result property="age" column="cage"></result> <!--告诉mybatis自己去查主人的信息 select = "执行一个查询猫主人的唯一标识,mybatis将自动调用指定的sql将employee查出来"; com.wkl.dao.EmployeeDao.getEmployee:需要传入人员id column:指定那一列的数据值传过去 --> <association property="employee" select="com.wkl.dao.EmployeeDao.getEmployee" column="person"></association> </resultMap>
结果;
7.1.2:Collection--分段查询
<!--public Employee getEmployee5(Integer id);--> <select id="getEmployee5" resultMap="hahah"> select * from t_employee where id = #{id} </select> <resultMap id="hahah" type="com.wkl.dao.EmployeeDao"> <id property="id" column="name"></id> <result property="name" column="name"></result> <result property="email" column="email"></result> <!--通过主人查猫--> <collection property="cats" select="com.wkl.dao.CatDao.getCat" column="id"></collection> </resultMap>
• 分步查询 的时候通过 column 指定,将对应的列的数据传递过去,我们有时需要传递多列数据 。• 使用column= {key1=column1,key2=column2…} 的形式
7.2:延迟加载
当猫对象有一个属性是Employee类;那么如果只需要查询猫名字的时候,在分步查询时不需要mybatis将猫主人信息查出来;这就是延迟加载
<!--重要的配置--> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
8:动态sql
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
8.1:if
<!--根据传入的对象,加入employee中某属性有值,就按照该属性取值--> <!--public Employee getEmployeeByCondition(Employee ee);--> <select id="getEmployeeByCondition" resultMap="employeeMap"> select * from t_employee where 1=1 /*test="" 编写判断条件 id!=null取出javabean中的id属性值*/ <if test="id!=null"> and id > #{id} </if> /*ognl表达式,第一个name是数据库字段,第二个是传入的javabean的属性*/ <if test="name!='' and name!=null"> and name like #{name} </if> </select>
8.2:where
where标签可以自动的为我们减去不需要的and链接符合增加where判断关键字
<!--根据传入的对象,加入employee中某属性有值,就按照该属性取值--> <!--public Employee getEmployeeByCondition(Employee ee);--> <select id="getEmployeeByCondition" resultMap="employeeMap"> select * from t_employee <!--test="" 编写判断条件 id!=null取出javabean中的id属性值--> <where> <if test="id!=null"> and id > #{id} </if> <!--ognl表达式,第一个name是数据库字段,第二个是传入的javabean的属性--> <if test="name!='' and name!=null"> and name like #{name} </if> </where> </select>
8.3:trim标签
<!--prefix="" 前缀;为我们的sql整体填一个前缀 prefixOverrides="" 去除整体字符前边多余的前缀 suffix="" 后缀;为sql整体加一个后缀 suffixOverrides="" 去除整体字符后边多余的后缀--> <trim prefix="where" prefixOverrides="and" suffix="" suffixOverrides=""> <if test="id!=null"> and id > #{id} </if> <!--ognl表达式,第一个name是数据库字段,第二个是传入的javabean的属性--> <if test="name!='' and name!=null"> and name like #{name} </if> </trim>
8.4:foreach
<!--public List<Employee> getEmployeeByIds(@Param("ids") List ids);--> <select id="getEmployeeByIds" resultMap="employeeMap"> select * from t_employee where id in <!-- collection="ids" :标识遍历的集合 close="":以什么结束; open="":以什么开始 index="i":索引 如果遍历的是一个list: index:指定当前的变量保存了当前的索引 item:保存当前遍历的变量的值 如果遍历的是一个map: index:指定的变量就是保存了当前遍历的元素的key; item:就是保存当前遍历元素的value item="变量名":每次便利店额元素的值; separator:每次遍历的分隔符 --> <foreach collection="ids" close=")" item="id" open="(" separator=","> #{id} </foreach> </select>
8.5:choose分支选择
相当于if---elase
<!--public List<Employee> getEmployeeByChoose(Employee ee);--> <select id="getEmployeeByChoose" resultMap="employeeMap"> select * from t_employee <where> <choose> <when test="id!=null"> id = #{id} </when> <when test="name!=null and !name.equals("")"> name =#{name} </when> <otherwise> 1=1 </otherwise> </choose> </where> </select>
8.6:set标签动态修改
<!--public List<Employee> getEmployeeByIds(@Param("ids") List ids);--> <update id="updateEmployee"> update t_employee <!--set标签可以动态的将修改的语句最后的逗号去掉--> <set> <if test="name!='' and name!=null"> name=#{name}, </if> <if test="email!='' and email!=null"> email = #{email}, </if> </set> <where> id = #{id} </where> </update>
8.7:mybatis的ognl表达式以及_parameter参数和_databaseId参数
OGNL( Object Graph Navigation Language )对象图导航语言,这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的EL,SpEL等
访问对象属性: person.name
调用方法: person.getName()
调用静态属性/方法: @java.lang.Math@PI
@java.util.UUID@randomUUID()
调用构造方法: new com.atguigu.bean.Person(‘admin’).name
运算符: +,-*,/,%
逻辑运算符: in,not in,>,>=,<,<=,==,!=
注意:xml中特殊符号如”,>,<等这些都需要使用转义字符
访问集合属性:
类型 | 伪属性 | 伪属性对应的 Java 方法 |
List、Set、Map | size、isEmpty | List/Set/Map.size(),List/Set/Map.isEmpty() |
List、Set | iterator | List.iterator()、Set.iterator() |
Map | keys、values | Map.keySet()、Map.values() |
Iterator | next、hasNext | Iterator.next()、Iterator.hasNext() |
_parameter:代表传入的参数;
传入单个参数;_parameter就代表这个参数
传入多个参数:_parameter就代表多个参数集合起来的map
_databaseId:代表当前环境
这样就可以根据不同的数据库厂商构建特定的语句
8.8:sql标签,可重用的标签
<!--提取可重用的sql--> <sql id="selectsql"> select * from t_employee </sql>