Mybatis入门学习

#{ } 和 ${ } 取值的区别

#{} : 是以预编译的形式,将参数设置到sql语句中,防止sql注入;

${} : 取出的值会直接拼接在sql语句中,会有安全问题;

resultMap自定义结果

resultTyperesultMap 只能同时用一个

<?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="com.garcon.dao.StudentMapper">

	<!--自定义某个javaBean的封装规则
	
	type:自定义规则的Java类型
	
	id:唯一id方便引用
	  -->
	<resultMap type="com.garcon.bean.Student" id="myStudent">
	
		<!--指定主键列的封装规则
		
		id定义主键会底层有优化
	 
		column:指定哪一列
		
		property:指定对应的javaBean属性
		  -->
		<id column="sid" property="sid"/>
		
		<!-- 定义普通列封装规则 -->
		<result column="last_name" property="lastName"/>
		
		<!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 -->
		<result column="gender" property="gender"/>
		<result column="hobby" property="hobby"/>
	</resultMap>
	
	<!-- resultMap:自定义结果集映射规则;  -->
	<select id="getStudentById"  resultMap="myStudent">
		select * from student where sid=#{sid}
	</select>
	
</mapper>

关联查询

查询 学生信息 的时候把对应的 班级信息 也查询出来

学生信息

package com.garcon.bean;

public class Student {

	private Integer sid;
	private String lastName;
	private String gender;
	private String hobby;
	private Sclass sclass;//班级信息
	
	...
	}

班级信息

package com.garcon.bean;

public class Sclass {

	private Integer cid;//班级id
	private String cName;//班级名称
	
	...
	}

Mapper接口

package com.garcon.dao;

public interface StudentMapper {

    //以sid查询学生信息
    public Student getStudentById(Integer sid);
}

resultMap 级联属性

<?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="com.garcon.dao.StudentMapper">

    <!--联合查询:级联属性封装结果集 -->
	<resultMap type="com.garcon.bean.Student" id="mystudent">
		<id column="sid" property="sid"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="hobby" property="hobby"/>
		<!--关联列用级联属性-->
		<result column="cid" property="sclass.cid"/>
		<result column="cname" property="sclass.name"/>
	</resultMap>
	
	<!--级联查询-->
	<select id="getStudentById"  resultMap="myStudent">
		SELECT
    		s.sid,
    		s.last_name,
    		s.gender,
    		s.hobby,
    		c.cid,
    		c.cname
		FROME
		    student s,
		    sclass c
		WHERE
		    s.sid=c.cid
		  AND
		    sid=#{sid}
	</select>
	
</mapper>

或 以下
resultMapassociation 属性

<?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="com.garcon.dao.StudentMapper">

    <!--使用association定义关联的单个对象的封装规则-->
	<resultMap type="com.garcon.bean.Student" id="myStudent">
		<id column="sid" property="sid"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="hobby" property="hobby"/>
		
		<!-- 
		association:可以指定联合的javaBean对象
		    property="sclass":指定哪个属性是联合的对象
		    javaType:指定这个属性对象的类型[不能省略]
		-->
		<association property="sclass" javaType="com.garcon.bean.Sclass">
			<id column="cid" property="cid"/>
			<result column="cname" property="cname"/>
		</association>
	</resultMap>
	
	<!--关联查询-->
	<select id="getStudentById"  resultMap="myStudent">
		SELECT
    		s.sid,
    		s.last_name,
    		s.gender,
    		s.hobby,
    		c.cid,
    		c.cname
		FROME
		    student s,
		    sclass c
		WHERE
		    s.sid=c.cid
		  AND
		    sid=#{sid}
	</select>
	
</mapper>

关联查询 collection

查询班级信息的同时查出班级所对应的学生信息

学生类

package com.garcon.bean;

public class Student {

	private Integer sid;
	private String lastName;
	private String gender;
	private String hobby;
	private Sclass sclass;//班级信息
	
	...
	}

班级类

package com.garcon.bean;

public class Sclass {

	private Integer cid;//班级id
	private String cName;//班级名称
	private List<Student> students;
	
	...
	}

Mapper班级接口

package com.garcon.dao;

public interface SclassMapper {

    //以班级id查询班级
    public Sclass getSclassById(Integer cid);
}

sclassMapper.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="com.garcon.dao.SclassMapper">
	
 <!--嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则  -->
	<resultMap type="com.garcon.bean.Sclass" id="Mysclass">
		<id column="cid" property="cid"/>
		<result column="cname" property="cName"/>
		<!-- 
			collection定义关联集合类型的属性的封装规则 
			ofType:指定集合里面元素的类型
		-->
		<collection property="students" ofType="com.garcon.bean.Student">
			<!-- 定义这个集合中元素的封装规则 -->
			<id column="sid" property="sid"/>
			<result column="last_name" property="lastName"/>
			<result column="gender" property="gender"/>
			<result column="hobby" property="hobby"/>
		</collection>
	</resultMap>
 
	<select id="getSclassById" resultMap="Mysclass">
		SELECT
	        s.sid,
	        s.last_name,
	        s.gender,
	        s.hobyy,
	        c.cid
	        c.cname
		FROM
		    student s
		LEFT JOIN
		    sclass c
		ON 
		    s.cid=c.cid
		WHERE
		    c.cid=#{cid}
	</select>
	
</mapper>

分步查询 association

先以学生的 学号 查询学生信息,再以 学生信息中的班级编号 查询班级信息

班级接口

package com.garcon.dao;

public interface Sclass {

    //以班级id查询班级信息
    public Sclass getSclasstById(Integer cid);
}
  • StudentMapper.java 学生接口
package com.garcon.dao;

public interface StudentMapper {

    //以sid查询学生信息
    public Student getStudentById(Integer sid);
}

sclassMapper.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="com.garcon.dao.SclassMapper">
	
	<!--以班级号查询班级信息-->
	<select id="getSclassById" resultType="com.garcon.bean.Sclass">
        SELECT * FROM sclass WHERE cid=#{cid}
	</select>
	
</mapper>

studentMapper.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="com.garcon.dao.StudentMapper">
	
    <!-- 
        使用association进行分步查询:
		    1、先按照学生id查询学生工信息
	    	2、根据查询学生信息中的cid值去班级表查出班级信息
	    	3、班级设置到学生中;
	 -->
	 
	 <resultMap type="com.garcon.bean.Student" id="Mystudent">
	 	<id column="sid" property="sid"/>
	 	<result column="last_name" property="lastName"/>
	 	<result column="gender" property="gender"/>
	 	<result column="hobby" property="hobby"/>
	 	
	 	<!-- 
	 	    association:定义关联对象的封装规则
	 	    	select:表明当前属性是调用select指定的方法查出的结果
	 	    	column:指定将哪一列的值传给这个方法
	 		
	 	   	流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
	 	 -->
 		<association property="dept" 
	 		select="com.garcon.dao.SclassMapper.getSclassById"
	 		column="cid">
 		</association>
	 </resultMap>
	
	 <select id="getStudentById" resultMap="Mystudent">
	 	SELECT * FROM student WHERE sid=#{sid}
	 </select>
	
</mapper>

分步查询 collection

先以 班级编号 查询班级信息,再以 班级编号 查询班级的所有学生信息

SclassMapper班级接口

package com.garcon.dao;

public interface Sclass {

    //以班级id查询班级信息
    public Sclass getSclasstById(Integer cid);
}

StudentMapper学生接口

package com.garcon.dao;

public interface StudentMapper {

    //以班级编号查询学生信息
    public List<Student> getStudentByClassId(Integer sid);
}

sclassMapper.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="com.garcon.dao.SclassMapper">
	
    <!-- collection:分段查询 -->
	<resultMap type="com.garcon.bean.Sclass" id="mySclass">
		<id column="cid" property="cid"/>
		<id column="cname" property="cName"/>
		<collection property="students" 
			select="com.garcon.dao.StudentMapper.getStudentByClassId"
			column="cid" fetchType="lazy"></collection>
	</resultMap>
 
	<select id="getSclasstById" resultMap="mySclass">
		select cid,cName from sclass where cid=#{cid}
	</select>
	
	<!--
	    扩展:
	    多列的值传递过去:
			将多列的值封装map传递;
			column="{key1=column1,key2=column2}"
			如:
			<collection 
			    property="" 
    			select=""
    			column="{key1=column1,key2=column2}"
    			fetchType="lazy">
    		</collection>
			
		    fetchType="lazy":表示使用延迟加载;

				- lazy:延迟
				- eager:立即

	 -->
	
</mapper>

studentMapper.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="com.garcon.dao.StudentMapper">
	
	<!--以班级编号查询所有学生-->
	 <select id="getStudentById" resultType="com.garcon.bean.Student">
	 	SELECT * FROM student WHERE class_id=#{class_id}
	 </select>
	
</mapper>

分步查询 延迟加载

适用情况:假如查看学生信息的时候不加载班级信息,当需要查看学生的班级信息的时候再加载班级信息

  • 在分步查询的基础上,在mybatis的全局配置文件的settings设置项中添加如下设置即可
<settings>
		<!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
</settings>

鉴别器 discriminator

鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为

  • 如果查出的是女生:就把班级信息查询出来,否则不查询;如果是男生,把last_name这一列的值赋值给 hobby;
  • studentMapper.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="com.garcon.dao.StudentMapper">
    <!-- 
		鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为
		封装Student:
			如果查出的是女生:就把班级信息查询出来,否则不查询;
			如果是男生,把last_name这一列的值赋值给 hobby;
	 -->
	 <resultMap type="com.garcon.bean.Student" id="mystudent">
	 	<id column="sid" property="sid"/>
	 	<result column="last_name" property="lastName"/>
	 	<result column="gender" property="gender"/>
	 	<result column="hobby" property="hobby"/>
	 	
	 	<!--
	 		column:指定判定的列名
	 		javaType:列值对应的java类型 
	 		-->
	 	<discriminator javaType="string" column="gender">
	 		<!--女生  resultType:指定封装的结果类型;不能缺少。/resultMap-->
	 		<case value="女" resultType="com.garcon.bean.Student">
	 			<association property="sclass" 
			 		select="com.garcon.dao.SclassMapper.getSclasstById"
			 		column="class_id">
		 		</association>
	 		</case>
	 		<!--男生 ;如果是男生,把last_name这一列的值赋值给hobby; -->
	 		<case value="男" resultType="com.garcon.bean.Student">
		 		<id column="id" property="id"/>
			 	<result column="last_name" property="lastName"/>
			 	<result column="last_name" property="hobby"/>
			 	<result column="gender" property="gender"/>
	 		</case>
	 	</discriminator>
	 </resultMap>
  • sclassMapper.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="com.garcon.dao.SclassMapper">
	
	<!--以班级号查询班级信息-->
	<select id="getSclassById" resultType="com.garcon.bean.Sclass">
        SELECT * FROM sclass WHERE cid=#{cid}
	</select>
	
</mapper>

动态SQL

if

<!--test:判断表达式(OGNL)-->
<if test=""></if>

<!--
    应用场境:按条件查询学生,
        如果参数中有sid则查询条件带上sid
        如果参数中有last_name则查询条件带上last_name
        如果参数中有gender则查询条件带上gender
-->

<select id="getStudent" resultType="com.garcon.dao.StudentMapper">
	 	select * from student
	 	<!-- where -->
	 	<where>
		 	<if test="sid!=null">
		 		sid=#{sid}
		 	</if>
		 	<if test="lastName!=null AND lastName!=''">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="hobby!=null and hobby.trim()!=''">
		 		and hobby=#{hobby}
		 	</if> 
		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	and gender=#{gender}
		 	</if>
	 	</where>
</select>

where

  • 去除查询条件中多余的第一个 andor
<!--
    检查以下sql语句
-->
<select id="getStudent" resultType="com.garcon.dao.StudentMapper">
	 	select * from student
	 	where
		 	<if test="sid!=null">
		 		sid=#{sid}
		 	</if>
		 	<if test="lastName!=null AND lastName!=''">
		 		and last_name like #{lastName}
		 	</if>
</select>
<!--
    可以发现,当以上参数 sid 为空时,sql语句就变成了:
        select * from student where and last_name=?
        多出的 and 语法错误;
    解决以上情况可以加标签<where></where>:
    把所有的<if></if>条件都放在<where></where>标签中,可以去除第一个 and 和 or 如下:
-->        
<select id="getStudent" resultType="com.garcon.dao.StudentMapper">
	 	select * from student
	 	<where>
		 	<if test="sid!=null">
		 		sid=#{sid}
		 	</if>
		 	<if test="lastName!=null AND lastName!=''">
		 		and last_name like #{lastName}
		 	</if>
		 </where>
</select>

trim

<!--
    检查以下sql语句
-->
<select id="getStudent" resultType="com.garcon.dao.StudentMapper">
	 	select * from student
	 	where
		 	<if test="sid!=null">
		 		sid=#{sid} and
		 	</if>
		 	<if test="lastName!=null AND lastName!=''">
		 		last_name like #{lastName}
		 	</if>
</select>

<!--
    可以发现,当以上参数 lastName 为空时,sql语句就变成了:
        select * from student where sid=? and
        结尾多出的 and 语法错误;
    解决以上情况可以加标签<trim></trim>:
    
        <trim prefix="" suffixOverrides="" suffix="" suffixOverrides=""></trim>
        
        后面多出的and或者or where标签不能解决 
    	 	prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。
    	 			prefix给拼串后的整个字符串加一个前缀 
    	 	prefixOverrides="":
    	 			前缀覆盖: 去掉整个字符串前面多余的字符
    	 	suffix="":后缀
    	 			suffix给拼串后的整个字符串加一个后缀 
    	 	suffixOverrides=""
    	 			后缀覆盖:去掉整个字符串后面多余的字符
    如下:
-->  
<select id="getStudent" resultType="com.garcon.dao.StudentMapper">
	 	select * from student
	 	<trim prefix="where" suffixOverrides="and">
		 	<if test="sid!=null">
		 		sid=#{sid} and
		 	</if>
		 	<if test="lastName!=null AND lastName!=''">
		 		last_name like #{lastName}
		 	</if>
		 </trim>
</select>

choose

<!--
    使用场景:
        如果参数中的id不为空就以id为条件查询,如果name不为空就已以name做查询条件
        如下:
-->
<select id="getStudent" resultType="com.garcon.dao.StudentMapper">
	 	select * from student 
    <where>
	 	<!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
        <choose>
	 		<when test="id!=null">
	 				sid=#{sid}
	 		</when>
	 		<when test="lastName!=null">
	 				last_name like #{lastName}
	 		</when>
	 		<when test="hobby!=null">
	 				hobby = #{hobby}
	 		</when>
	 			<!--如果以上条件都不满足,使用如下条件-->
	 		<otherwise>
	 				gender = '女'
            </otherwise>
        </choose>
    </where>
</select>

update-set

如果javaBean中哪个属性带了值就更新那个字段

<update id="updateStudent">
	 	<!-- Set标签的使用 -->
	 	update student 
		<set>
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="hobby!=null">
				hobby=#{hobby},
			</if>
			<if test="gender!=null">
				gender=#{gender}
			</if>
		</set>
		where id=#{id} 
</update>

update-trim

<update id="updateStudent">
		update student 
		<trim prefix="set" suffixOverrides=",">
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="email!=null">
				email=#{email},
			</if>
			<if test="gender!=null">
				gender=#{gender}
			</if>
		</trim>
		where id=#{id}
	 </update>

select-foreach

<select id="getStudent" resultType="com.garcon.bean.Student">
	 	select * from student
	 	<!--
	 		collection:指定要遍历的集合:
	 			list类型的参数会特殊处理封装在map中,map的key就叫list
	 		item:将当前遍历出的元素赋值给指定的变量
	 		separator:每个元素之间的分隔符
	 		open:遍历出所有结果拼接一个开始的字符
	 		close:遍历出所有结果拼接一个结束的字符
	 		index:索引。遍历list的时候是index就是索引,item就是当前值
	 				      遍历map的时候index表示的就是map的key,item就是map的值
	 		
	 		#{变量名}就能取出变量的值也就是当前遍历出的元素
	 	  -->
	 	<foreach collection="ids" item="item_id" separator=","
	 		open="where id in(" close=")">
	 		#{item_id}
	 	</foreach>
	 </select>

insert-foreach

批量插入

<!--
	 MySQL下: 
	 第一种方法 
	 可以foreach遍历   mysql支持values(),(),()语法-->
	<insert id="addStudents">
	 	insert into student(last_name,gender,hobby,class_id) 
		values
		<foreach collection="students" item="student" separator=",">
			(#{student.lastName},#{student.gender},#{student.hobby},#{student.sclass.cid})
		</foreach>
	 </insert>
	 
<!--
    第二种方法
    这种方式需要数据库连接属性allowMultiQueries=true;
	 	这种分号分隔多个sql可以用于其他的批量操作(删除,修改) -->
    <insert id="addEmps">
	 	<foreach collection="emps" item="emp" separator=";">
	 		insert into student(last_name,gender,hobby,class_id)
	 		values((#{student.lastName},#{student.gender},#{student.hobby},#{student.sclass.cid})
	 	</foreach>
	 </insert> 
	 
	 
	 
<!-- 
    Oracle数据库批量保存: 
	 	Oracle不支持values(),(),()
	 	Oracle支持的批量方式
	 	1、多个insert放在begin - end里面
	 		begin
			    insert into employees(employee_id,last_name,email) 
			    values(employees_seq.nextval,'test_001','test_001@atguigu.com');
			    insert into employees(employee_id,last_name,email) 
			    values(employees_seq.nextval,'test_002','test_002@atguigu.com');
			end;
			
		2、利用中间表:
			insert into employees(employee_id,last_name,email)
		       select employees_seq.nextval,lastName,email from(
		              select 'test_a_01' lastName,'test_a_e01' email from dual
		              union
		              select 'test_a_02' lastName,'test_a_e02' email from dual
		              union
		              select 'test_a_03' lastName,'test_a_e03' email from dual
		       )
		       
		 oracle第一种批量方式
	 -->
	 <insert id="addEmps" databaseId="oracle">
	 	<foreach collection="emps" item="emp" open="begin" close="end;">
	 		insert into employees(employee_id,last_name,email) 
			    values(employees_seq.nextval,#{emp.lastName},#{emp.email});
	 	</foreach>
	 </insert>
	 	
	 	<!-- oracle第二种批量方式  -->
	 <insert id="addEmps" databaseId="oracle">
	 	insert into employees(employee_id,last_name,email)
            <foreach collection="emps" item="emp" separator="union"
	 			open="select employees_seq.nextval,lastName,email from("
	 			close=")">
	 				select #{emp.lastName} lastName,#{emp.email} email from dual
	 		</foreach>
	 </insert>

获取自增主键的值

方式一 :
使用insert标签的属性useGeneratedKeys="true" keyProperty="id"

<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
        insert into user(username,password,email) values(#{username},#{password},#{email})
</insert>

方式二 : 插入时先查询将要插入数据的自增id值

 <insert id="addUser" useGeneratedKeys="true" keyProperty="id">
        <selectKey order="AFTER" keyProperty="id" resultType="int">
            select last_insert_id()
        </selectKey>
        insert into user(username,password,email) values(#{username},#{password},#{email})
    </insert>

参数处理

单个参数

可以接受基本类型,对象类型,集合类型的值。这种情况 MyBatis可直接使用这个参数,不需要经过任何处理。

多个参数

任意多个参数,都会被MyBatis重新包装成一个Map传入。Map的key是param1,param2,0,1…,值就是参数的值。

命名参数

为参数使用@Param起一个名字,MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字

POJO

当这些参数属于我们业务POJO时,我们直接传递POJO

Map

我们也可以封装多个参数为map,直接传递

注意 : 当参数是一个Connection , List , Array数组时, 参数会封装成一个Map , key值为 : connection , list , array .

上一篇:pythonB站爬虫二(速度提升)


下一篇:uni-app使用推送功能