MyBatis三种开发方式
接口代理的开发方式(重点)
使用注解的开发方式(重点)
传统DAO实现类的开发方式(目前淘汰,因为分布式的使用)
mybatis中的sql
参数占位符:
#{}:先使用?占位,执行SQL时将具体值赋值给?
${}:拼SQL,会存在SQL注入问题
parameterType:
用于设置参数类型,该参数可以省略
SQL语句中特殊字符处理:
转义字符
<![CDATA[ 内容 ]]>:CD提示<select id="selectById" resultType="User">
select * from user where id = #{id};
<!--
select * from user where id = #{id};预编译,sql语句中用?占位
select * from user where id = ${id}; 拼接SQL
在<select>等标签中不能打ctrl+/注释,是不会完全注释gL语句的,必须用这种注释
parameterType属性: 传入参数的属性,可以省略,所以建议不写
resultType属性:方法的返回类型,主要是对象,如果是增删改返回影响行数的,不要写
当数据库字段名和类的成员变量名一致的时候,使用
select * from user where id <#lid}; 遇到<等符号,需要使用转义符
-->
</select>
事务
查询数据可以直接查不会出错
但是增删改必须要开启事务,因为在mybaits中默认不会自动提交
事务两种开启方式:
在sqlSessionFactory.openSession(true);
sqlSession.commit()
增删改查
删除
1.在接口中添加方法
2.在接口映射文件UserMapper.xml配置SQL语句
3.执行方法
1.在接口中添加方法
void deleteById(int id);
2.在接口映射文件UserMapper.xml配置SQL语句
<delete id="deleteById"> delete from user where id = #{id}; </delete>
3.执行方法
@Test
public void test3() throws IOException {
//因为要使用mybatis,所以要把配置文件mybatis-config.xml加载过来(在测试案例访问resoureces的资源,可以直接访问文件)
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//将这个文件转为流的形式,这个流会自动关闭,然后使用这个流获取连接,首先获得连接的builder对象
//这个builder需要new
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//到这步获得了连接的工厂类,接下来通过工厂类获得连接
SqlSession sqlSession = sqlSessionFactory.openSession();
//成功获得连接,使用这个连接将接口使用动态代理生成对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//因为是动态代理所以用.class
//用代理对象调用接口中的方法
mapper.deleteById(3);
//提示成功,但是实际上确删除不成功,这是因为mybatis的事务
//在进行增删改的操作,要提交事务,mybatis事务的自动提交默认时关闭的
//有两种设置事务的方法,1.在sqlSessionFactory.openSession(true);2.sqlSession.commit()
sqlSession.commit();
//关闭资源,只需要关闭sqlSession
sqlSession.close();
}
修改
int update(User user);
<update id="update">
UPDATE user
SET username = #{username},
birthday =#{birthday},
sex=#{sex},
address=#{address}
WHERE id = #{id};
</update>
@Test
public void test4() throws IOException {
//因为要使用mybatis,所以要把配置文件mybatis-config.xml加载过来(在测试案例访问resoureces的资源,可以直接访问文件)
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//将这个文件转为流的形式,这个流会自动关闭,然后使用这个流获取连接,首先获得连接的builder对象
//这个builder需要new
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//到这步获得了连接的工厂类,接下来通过工厂类获得连接
SqlSession sqlSession = sqlSessionFactory.openSession();
//成功获得连接,使用这个连接将接口使用动态代理生成对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//因为是动态代理所以用.class
//用代理对象调用接口中的方法
User user = new User(1, "cat", Date.valueOf("2022-01-11"), "男", "地球");
mapper.update(user);
//提示成功,但是实际上确删除不成功,这是因为mybatis的事务
//在进行增删改的操作,要提交事务,mybatis事务的自动提交默认时关闭的
//有两种设置事务的方法,1.在sqlSessionFactory.openSession(true);2.sqlSession.commit()
sqlSession.commit();
//关闭资源,只需要关闭sqlSession
sqlSession.close();
}
插入
插入并获取新的主键值
int add(User user);
<!--useGeneratedKeys 获取数据库中生成的主键 keyProperty 将获取到的主键放到那个属性中 -->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user
VALUES (null, #{username}, #{birthday}, #{sex}, #{address});
</insert>
@Test
public void test5() throws IOException {
//因为要使用mybatis,所以要把配置文件mybatis-config.xml加载过来(在测试案例访问resoureces的资源,可以直接访问文件)
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//将这个文件转为流的形式,这个流会自动关闭,然后使用这个流获取连接,首先获得连接的builder对象
//这个builder需要new
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//到这步获得了连接的工厂类,接下来通过工厂类获得连接
SqlSession sqlSession = sqlSessionFactory.openSession();
//成功获得连接,使用这个连接将接口使用动态代理生成对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//因为是动态代理所以用.class
//用代理对象调用接口中的方法
User user = new User(10086, "dog", Date.valueOf("1980-10-24"), "男", "地球");
System.out.println(user.getId());
int row = mapper.add(user);
System.out.println(row);
System.out.println(user.getId());
//提示成功,但是实际上确删除不成功,这是因为mybatis的事务
//在进行增删改的操作,要提交事务,mybatis事务的自动提交默认时关闭的
//有两种设置事务的方法,1.在sqlSessionFactory.openSession(true);2.sqlSession.commit()
sqlSession.commit();
//关闭资源,只需要关闭sqlSession
sqlSession.close();
}
多参数处理
当只有一个参数时,在xml中编写sql时可以使用传入的参数名,但是多参数的时候不能直接用参数名
select
//多参数
//报错Available parameters are [arg1, arg0, param1, param2]
//方案1,散装,用@Param给咱们的参数起个名字
//List<User> selectByCondition(@Param("username") String username, @Param("sex") String sex);
//方案2,使用对象封装
//List<User> selectByCondition(User user);
//方案3,使用Map集合封装
List<User> selectByCondition(Map<String,String> map);
<select id="selectByCondition" resultType="com.jwl.pojo.User">
<!--
select * from user where username = #{username} and sex = #{sex};
//报错Available parameters are [arg1, arg0, param1, param2]
因为传多参数时,默认是用arg或者param这种形式,arg从0开始,param从1开始
这样用:select * from user where username = #{arg0} and sex = #{arg1};
但是如果参数过多,使用这种默认方式太过麻烦,要是我们还想使用传入的参数名,有三种解决方案:
1.散装。在接口中定义参数
-->
select * from user where username like #{username} and sex = #{sex};
</select>
动态sql
sql语句并不是固定不变的,要根据条件编写合适的sql语句
if标签
select if标签 where标签
//动态sql
List<User> selectByIf(@Param("username") String username, @Param("sex") String sex);
<select id="selectByIf" resultType="com.jwl.pojo.User">
<!--
两个条件同时满足时,成功查询
若是两个都不输入则sql为select * from user where,出现报错
但是,若是不输入username ,只输入sex, 那么拼接的sql将为select * from user where and sex = ? 出现报错
思考:都不输入时,这个where怎么去掉? 只输入sex时,and怎么去掉?
mybatis为了解决这个问题,把where做成了标签<where>
<where>在需要where的时候会补上,并且将多余的and或or带走
(需要他的时候就会出现,并且帮忙解决其他麻烦,比如带走and ,像极了女神的舔狗们)
-->
select * from user
<where>
<if test="username!=null and username != ''">
username = #{username}
</if>
<if test="sex != null and sex !=''">
and sex = #{sex};
</if>
</where>
</select>
update set标签
//这样new一个user,再通过set方法传入数据,如果没传入数据的字段就会是null,会把数据库中不准备修改的数据变为Null
//为了避免这种情况,也要加入if标签来判断
int updateByIf(User user);
<update id="updateByIf">
<!--
这样new一个user,再通过set方法传入数据,如果没传入数据的字段就会是null,会把数据库中不准备修改的数据变为Null
为了避免这种情况,也要加入if标签来判断
UPDATE user
SET username = #{username},
birthday =#{birthday},
sex=#{sex},
address=#{address}
WHERE id = #{id};
加上if标签,还是存在一个问题,每一个if标签中sql中都有一个逗号,会产生语法错误
mysbatis将set做成标签<set>代替set同时去掉多余的逗号
-->
UPDATE user
<set>
<if test="username !=null and username != ''">
username = #{username},
</if>
<if test="birthday !=null"><!--birthday这里不能判断为'',因为Date类型和String类型比较会报错 -->
birthday = #{birthday},
</if>
<if test="sex !=null and sex != ''">
sex = #{sex},
</if>
<if test="address !=null and address != ''">
address = #{address},
</if>
</set>
WHERE id = #{id};
</update>
批量删除 foreach标签
void deleteByIds(int[] ids);
<!--
批量删除,传入的参数是一个数组,思考一下,where中应该用in
在mybatis中有专门的对于数组,集合的标签<foreach>
我们原意是要 delete from user where id in (?,?,?);
collection表示传入的数组或者集合,数组默认名字叫做array,如果是集合默认名字为list
item表示数组或集合中的一项
open遍历前加的内容
close遍历后加的内容
separator表示分隔符
-->
<delete id="deleteByIds">
delete from user where id in
<!--直接写在collection中直接写ids会报错,必须要么用散装方式给参数设定个名字,要么默认用array -->
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
choose标签
跟java的switch类似
List<User> selectBySex(int sex);
<select id="selectBySex" resultType="com.jwl.pojo.User">
select * from user
<where>
<choose>
<when test="sex==1">
sex = '男';
</when>
<when test="sex==0">
sex = '女';
</when>
<otherwise>
sex = '女';
</otherwise>
</choose>
</where>
</select>
sql标签
<select id="selectAll" resultType="User">
select
<include refid="useAll"/>
from user;
</select>
<!-- sql标签:可以抽取一部分的公用代码
id属性:唯一的标识,别的地方可以通过这个id找到这个标签
include标签:引入sql标签抽取的内容
refid属性:抽取的sql标签的id
像下面这个sql标签就抽取的*的内容
-->
<sql id="useAll">
id
,username,birthday,sex,address
</sql>
ResultMap
在上述的例子中都是数据库字段名和实体类名相同,查询方便
但是很多情况下数据库字段名和实体类名不同
因为数据库字段名和实体类的属性名不一致,查到的数据封装不到Order中,
解决方法有三种
1.取别名,在写sql时,取对应实体类的别名
2.在mybaits配置文件中的标签中设置自动将数据库和实体类名称转换< setting name=“mapUnderscoreToCamelCase” value=“true”/>,默认为关闭
3.使用resultMap
<settings>
<!--在控制台显示SQL语句 打印日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<resultMap id="OrderMap" type="Order">
<id column="o_id" property="oId"/>
<result column="user_id" property="userId"/>
<result column="create_time" property="createtime"/>
</resultMap>
<select id="selectAllBy" resultMap="OrderMap">
select * from tb_order;
</select>
最后
如果你对本文有疑问,你可以在文章下方对我留言,敬请指正,对于每个留言我都会认真查看。