1. 参数传递
$与#的区别
1.$号只能读取对象里面的属性值,并且是通过getter方法读取
2.#会对传递的参数加上引号,$号不会 $会有sql注入问题
如果作为对象传递进去,需要指定参数类型,就可以直接获取属性,map也是对象,,如果使用@param进行标记,获取属性就需要使用类。属性来获取,,
1.第一种方式 匿名参数 顺序传递参数0 ,1 或者arg0 arg1 或者param1 param2
List<Employee> selectByGenderAndAge(Short gender,String age );
<select id="selectByGenderAndAge" resultMap="BaseResultMap" >
select * from employee where gender = #{param1} and age = #{param2}
</select>
第二种方式 使用@Param注解 按照参数名引用
List<Employee> selectByGenderAndAge( @Param("gender") Short gender,@Param("age") String age );
<select id="selectByGenderAndAge" resultMap="BaseResultMap" >
select * from employee where gender = #{gender} and age = #{age}
</select>
3.使用Map传递参数,k为名称,v存执 可以直接引用k
Map params = new HashMap<>();
params.put("gender",gender);
params.put("age",age);
List result= employeeMapper.selectByMapParams(params);
List<Employee> selectByMapParams(Map params);
<select id="selectByMapParams" resultMap="BaseResultMap" parameterType="map">
select * from employee
where gender = #{gender} and age = #{age}
</select>
如果要使用map中的k 和value 都作为参数,使用foech遍历
4.用过java bean传递多个参数,使用时parameterType指定为对应的bean类型即可,可以在mybatis.xml配置文件中配置别名,一般配置包,直接实用类名即可
List <Employee> selectByBeans(Employee employee);
<select id="selectByBeans" resultMap="BaseResultMap" parameterType="com.wg.demo.po.Employee">
select *
from employee where gender = #{gender} and age = #{age}
</select>
5.直接使用JSON传递参数,如果传来的是Bean对象转成的json,可以直接使用,参数类型使用json解析器中的类
List <Employee> findByJSONObject(JSONObject params);
<select id="findByJSONObject" resultMap="BaseResultMap" parameterType="com.alibaba.fastjson.JSONObject">
select *
from employee where gender = #{gender} and age = #{age}
</select>
6.传递集合类型参数List、Set、Array 通过forech 遍历
List <Employee> findByList(List list);
<select id="findByList" resultMap="BaseResultMap" >
SELECT * from employee where age in
<foreach collection="list" open="(" separator="," close=")" item="age">
#{age}
</foreach>
</select>
主键返回的方法
1.自增主键
<!--
useGeneratedKeys:是否返回主键
keyProperty:主键返回了给User哪个属性
keyColumn:指定列 插入过后 获得uid这一列的值 作为主键返回 赋值给User对象的uid属性
-->
<insert id="insert" parameterType="cn.cdqf.pojo.User" useGeneratedKeys="true" keyProperty="uid"
keyColumn="uid">
insert into mybaties2 (uname,age) values(#{uname},#{age})
</insert>
--------------------------------------------------------------------
public void insert() {
User user = new User("zhangsan", 25);
SqlSession sqlSession = SqlSessionUtil.sqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
int insert = userDao.insert(user);
sqlSession.commit();
System.out.println("insert = " + user.getUid());
SqlSessionUtil.close(sqlSession);
}
2. 非自增主键
非自增主键需要在执行insert sql之前指定一个主键值 给要插入的记录,
<insert id="insert" parameterType="cn.cdqf.pojo.User">
<!--order:在数据插入前 还是插入后
oracle:before
序列号(类似于在java里面写一个生成id的方法),不在表里面生成
插入数据库之前就会触发序列号自增,先插入了再去拿,
A:想插入数据 先去拿id 10
B:像插入 拿到11
Mysql:插入过程生成id after ,如果使用before 要注意,如果是新的connection并且第一次插入,获取的主键是零
-->
//keyColumn 主键, keyProperty返回给对象的哪个属性 resultType根据表中的填
<selectKey keyColumn="uid" keyProperty="uid" resultType="int" order="AFTER">
select last_insert_id();<!--获得当前mysql的这个库最后一次插入数据库自增的id-->
</selectKey>
insert into user(uname) values(#{uname})
</insert>
--------------------------------------------------------------------
public void insert() {
User user = new User("zhangsan", 25);
SqlSession sqlSession = SqlSessionUtil.sqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
int insert = userDao.insert(user);
sqlSession.commit();
System.out.println("insert = " + user.getUid());
SqlSessionUtil.close(sqlSession);
}
mybais转义
xml中写uid<{uid}报错 认为是标签的开头 使用<![CDATA[代码]]> 进行包裹转义
<![CDATA[代码]]>
常见标签
//test中条件满足 ,if标签中的sql语句才会出现
<if test="name!=null and name!=''"></if> :里面的条件满足才执行标签里面sql语句
//where标签,给语句开头加上where关键字 并且去掉第一个and
如果名字不为空或者不为空字符串,则根据名字模糊查询,age不为空且大于零 就看年龄大于传入值查询
<select id="queryByNameAndAge" resultType="cn.dream.pojo.User">
select * from mybaties2
<where>
<if test="name!=null and name != '' ">
and uname like concat('%',#{name},'%')
</if>
<if test="age != null and age>0">
and age>#{age}
</if>
</where>
</select>
//<set></set> 开头加上加上set关键字 去掉末尾的,
<update id="set1" parameterType="User">
update mybaties2
<set>
<if test="user.uname!=null">
uname=#{user.uname},
</if>
<if test="user.age != null" >
age=#{user.age},
</if>
</set>
where uid=#{user.uid}
</update>
//<trim></trim> prefix前 suffix 后 加关键字 ;或者 prefixOverrides suffixOverrides覆盖掉前后多余某个字符
<select id="queryByNameAndAge" resultType="user" >
select <include refid="BaseSql"></include> from mybaties2
<trim prefix="where" prefixOverrides="and" >
<if test="name!=null and name != '' ">
and uname like concat('%',#{name},'%')
</if>
<if test=" age != null and age!=''">
and age > #{age}
</if>
</trim>
</select>
//<choose><when>A</when><otherwise>B</otherwise></choose> when条件满足执行A 否则执行B
<select id="queryByNameAndAge2" resultType="cn.dream.pojo.User">
<bind name="aa" value="'%'+uname+'%'"/>
select * from mybaties2
<where>
<choose>
<when test="uname!=null and uname!=''" >
uname like #{aa}
</when>
<otherwise>
and age>#{age}
</otherwise>
</choose>
</where>
</select>
#把%uname参数 %拼接起来赋值给aaa 使用就只需要#{aaa} ,方便拼接
<bind name="aaa" value="'%'+uname+'%'"/>
#相当于定义一个sql语句可以多出引用
<sql id='a'>定义sql</sql> 其它地方直接使用<include refid='a'></include>
//<foreach></foreach> 集合数组 map//使用方法类似jsp中的el表达式
//数组集合
List<User> userList = Arrays.asList(new User("张三", 20), new User("liming", 60));
<update id="batchInsert">
INSERT INTO mybaties2 (uname,age) values
<foreach collection="values" item="user" separator=",">
(#{user.uname},#{user.age})
</foreach>
</update>
//使用map中的key和value
void batchInsert2(@Param("map") Map<String,Object> map);
<insert id="batchInsert2">
insert into mybaties2 (uname,age) values
<foreach collection="map" index="key" item="value" separator="," >
(#{key},#{value})
</foreach>
</insert>
//map使用value
<foreach collection="map.values" item="key" separator="," >
(#{key}
</foreach>
ResulltMap结果映射
如果Bean的属性名与数据库中不一致,直接查询属性值会设置不进去
解决方法1
通过查询时给字段取别名,这样查询出来的字段就与属性名一致了
2.ResultMap映射
属性与字段名不匹配
<resultMap id="BaseMap1" type="Student">
<id column="s_id" property="sId"></id>
<result column="s_name" property="sName"></result>
<result column="t_id" property="tId"></result>
</resultMap>
一对一
//一个学生对应一个老师
<resultMap id="BaseMap1" type="Student">
<id column="s_id" property="sId"></id>
<result column="s_name" property="sName"></result>
<result column="t_id" property="tId"></result>
<association property="teacher" javaType="Teacher">
<id column="t_id" property="tId"></id>
<result column="t_name" property="tName"></result>
<result column="sex" property="sex"></result>
<result column="salary" property="salary"></result>
<result column="course" jdbcType="VARCHAR" property="course" javaType="String" ></result>
</association>
</resultMap>
在查询体中通过id调用
<select id="selectById" resultType="cn.dream.pojo.Student" resultMap="BaseMap1">
select s.*,t.* from student s JOIN teacher t on s.t_id=t.t_id where s.s_id=#{param1}
</select>
一对一的另一种形式 ,使用对应的Bean的查询方法
<resultMap id="BaseMap2" type="Student">
<id column="s_id" property="sId"></id>
<result column="s_name" property="sName" ></result>
<result column="t_id" property="tId" ></result>
//使用查询出来的学生id作为参数查询老师
<association property="teacher" javaType="Teacher" column="t_id" select="cn.dream.dao.TeacherDao.selectByPrimaryKey">
</association>
</resultMap>
<select id="selectById" resultType="cn.dream.pojo.Student" resultMap="BaseMap2">
select s.*,t.* from student s JOIN teacher t on s.t_id=t.t_id where s.s_id=#{param1}
</select>
一对多
一对多
//一个老师对应多个学生
<resultMap id="BaseResultMap2" type="cn.dream.pojo.Teacher">
<id column="t_id" jdbcType="INTEGER" property="tId" javaType="Int" />
<result column="t_name" jdbcType="VARCHAR" property="tName" />
<result column="sex" jdbcType="VARCHAR" property="sex" />
<result column="salary" jdbcType="FLOAT" property="salary" />
<result column="course" jdbcType="VARCHAR" property="course" />
<collection property="studentList" ofType="Student">
<id column="s_id" property="sId" jdbcType="INTEGER" javaType="Int" ></id>
<result column="s_name" property="sName"></result>
<result property="tId" column="t_id" ></result>
</collection>
</resultMap>
<select id="queryById" resultMap="BaseResultMap2">
select t.*,s.* from teacher t join student s on t.t_id=s.t_id
where t.t_id=#{tId}
</select>
延迟加载
开启延迟加载
关联关系中,可以通过配置达到按需加载
<setting name ="aggressiveLazyLoading" value="false"/>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
一二级缓存
缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力。跟Hibernate 一样,MyBatis 也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。
一级缓存
也叫本地缓存是sqlSession缓存 cache,默认开启
-
在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;
-
不同的 SqlSession 之间的缓存是相互隔离的;
-
用一个 SqlSession, 可以通过配置使得在查询前清空缓存;
在对应查询语句中 作出配置,就不会使用缓存 <select id="queryByNameAndAge" resultType="user" flushCache="true"> select <include refid="BaseSql"></include> from mybaties2 <trim prefix="where" prefixOverrides="and" suffix="" suffixOverrides=""> <if test="name!=null and name != '' "> and uname like concat('%',#{name},'%') </if> <if test=" age != null and age!=''"> and age > #{age} </if> </trim> </select>
-
任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。
二级缓存
是针对同一个sqlSessionfactory 中的多个sqlsession 会存储sql语句,
当发出同一个查询sql时 之前有的会自动返回之前查询到的值
默认关闭,开启缓存 在mybatis 配置文件中配置
<setting name="cacheEnabled" value="true"/>
哪个类要开启缓存就在哪个类的mapper中 加入 <cache/>标签
- 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;
- 不同的 SqlSession 之间的缓存是相互隔离的;
- 用一个 SqlSession, 可以通过配置使得在查询前清空缓存;
- 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。