mybatis作用简单来说就是简化jdbc,将jdbc的那些复杂。琐碎代码编程通透,简单,框架化的代码。
mybatis入门
首先如果是在建项目的时候就用了maven构建,那么可以直接在pom.xml配置文件中添加坐标,其中mybatis和mysql的坐标是必须的,junit测试单元和logback等其他坐标配置可以按需添加,如果在建项目的时候没有用maven构建,需要在后续的项目中添加maven构建的模块,名字也是pom.xml
上述解决后,便开始编写mybatis的核心配置文件。首先在resources中创建名为mybatis-config的xml文件。里面的代码模板如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--加载sql映射文件-->
<!--resource后面接的是映射文件路径-->
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
接着就是编写sql映射文件。在resources里面创建sql映射文件,命名格式为:表名Mapper,后缀为xml
其中sql映射文件里面的模板是如下代码形式:
<?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">
<!--
namespace:名称空间
id:sql语句的唯一标识
resulrType:返回结果类型
-->
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
这个结束后,开始编码。步骤为:
1.定义pojo类,类里面就是一个个java文件。
2.加载核心配置文件,获取SQLSessionFactory
3.获取SqlSession对象,执行sql语句
4.释放资源
模板代码:
//加载mybatis的核心配置文件,获取SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,用它来执行sql
SqlSession sqlSession=sqlSessionFactory.openSession();
//执行sql
//释放资源
sqlSession.close();
提示:在编写sql映射文件时,可能会有警告提示,原因可能是idea和数据库没有建立连接,所以建议开始就建连接。建立连接操作如下:
Mapper代理开发
Mapper代理开发也是为了简化上述代码。
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
上面这段代码就是原来的sql执行输出代码。
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
上面这个时用Mapper代理开发的sql执行输出代码。
mapper代理开发步骤:
1.定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下。下面图便是模板
提示
:在编译后,UserMapper接口和UserMapper.xml在同一目录下。
2.设置SQL映射文件的namespace属性为Mapper接口全限定名。
即如下图所示:
3.在Mapper接口中定义方法,方法名就是SQL映射文件中的sql语句中的id,并保证参数类型和返回值类型一致。
模板代码:
//加载mybatis的核心配置文件,获取SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,用它来执行sql
SqlSession sqlSession=sqlSessionFactory.openSession();
//执行sql
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
List<User> users=userMapper.selectAll();
//释放资源
sqlSession.close();
细节:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载。
eg:
这样在有很多sql映射文件时,可以用一行代码替代。
Mybatis核心配置文件
这个我不知道怎么讲,也说不清楚。索性贴配置的官网,在需要配置的时候直接查,不会的百度罢了。
配置链接:配置_MyBatis中文网
mybatis写项目必备插件:MyBatisX
查询
eg1:查询所有
<select id="函数名字" resultType="函数返回类型">
select *
from tb_brand(表名);
</select>
注意
如果数据库表的字段名称和实体类的属性名称不一样,则不能自动封装 数据。
解决办法:起别名,对不一样的列名起别名,让别名和实体类的属性名一样
<select id="函数名字" resultType="函数返回类型">
select brand_name as brandName
from tb_brand(表名);
</select>
缺点:每次查询都要定义一次别名
解决办法:sql片段
<sql id="brand_column">
id,brand_name as brandName
</sql>
<select id="函数名字" resultType="函数返回类型">
select
<include refid="brand_column"/>
from tb_brand(表名);
</select>
缺点:不灵活
解决办法:resultMap:1.定义<resultMap>标签,2.在select标签中,使用 resulrMap属性替换resultType属性
//id:唯一标识
//type:映射的类型,支持别名
<resultMap id="brandResultMap" type="brand">
//id:完成主键字段的映射,column:表的列名,property:实体类 的属性名
//result:完成一般字段的映射
<result column="brand_name" ` property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="函数名字" resultMap="brandResultMap">
select *
from tb_brand(表名);
</select>
eg2:查询详情
<!--
参数占位符:
1.#{}:会将其替换为?。可以防止SQL注入
2.${}:拼SQL,会存在SQL注入问题
3.使用时机:参数传递的时候用#{},表名或者列名不固定的情况下用 ${}
-->
<select id="函数名字" resultType="函数返回类型">
select *
from tb_brand(表名) where id=#{id};
</select>
<!--
特殊字符处理:
1.转义字符:
2.CDATA区:
-->
特殊字符处理如果忘了,可以csdn上面搜。
eg3:条件查询
<select id="selectByCondition" resultMap="brandResuleMap">
select *
from tb_brand
where
status=#{status}
and company_name like #{companyName}
and brand_name like #{brandName};
</select>
条件查询的参数接收问题
1.散装参数:如果方法中有多个参数,需要使用@Param(“SQL参数占位符名 称”)
eg:
List<Brand> selectByCondition(@Param("status") int status,@Param("companyName") int companyName)
2.对象参数:对象的属性名称要和参数占位符名称一致
eg:
List<Brand> selectByCondition(Brand brand);
3.map集合参数:需要保证SQL中的参数名和map集合的键的名称对应上,即可 设置成功
eg:
List<Brand> selectByCondition(Map map);
eg4:动态条件查询
动态查询:SQL语句会根据输入或者外部条件的变化而变化。
实现动态SQL的四个标签:
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
if的使用:
eg:
<select id="selectByCondition" resultMap="brandResuleMap">
select *
from tb_brand
where
<if test="status!=null">
status=#{status}
</if>
<if test="companyName!=null and companyName!=''">
and company_name like #{companyName}
</if>
<if test="brandName!=null and brandName!=''">
and brand_name like #{brandName};
</if>
</select>
讲解:if:条件判断
test:逻辑表达式
但是上述动态sql语句有问题,如果第一个if标签没成立,那么这个sql语句就是错的。
解决办法:
方法1:恒等式
<select id="selectByCondition" resultMap="brandResuleMap">
select *
from tb_brand
where 1=1
<if test="status!=null">
and status=#{status}
</if>
<if test="companyName!=null and companyName!=''">
and company_name like #{companyName}
</if>
<if test="brandName!=null and brandName!=''">
and brand_name like #{brandName};
</if>
</select>
方法2:where标签代替where关键字
<select id="selectByCondition" resultMap="brandResuleMap">
select *
from tb_brand
<where>
<if test="status!=null">
and status=#{status}
</if>
<if test="companyName!=null and companyName!=''">
and company_name like #{companyName}
</if>
<if test="brandName!=null and brandName!=''">
and brand_name like #{brandName};
</if>
</where>
</select>
eg5:单条件动态查询
<select id="selectByCondition" resultMap="brandResuleMap">
select *
from tb_brand
<where>
<choose><!--类似switch-->
<when test="status!=null"><!--类似case-->
and status=#{status}
</when>
<when test="companyName!=null and companyName!=''">
and company_name like #{companyName}
</when>
<when test="brandName!=null and brandName!=''">
and brand_name like #{brandName};
</when>
</where>
</select>
添加
<insert id="add">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
这时候可能sql执行了,但是数据没有添加到数据库中,这很有可能是没有提交事务,导致发生sql回滚,然后数据就会添加不进去。
所以可以在执行的方法中,在释放资源前进行事务提交;即代码
//提交事务
sqlSession.commit();
像下面这样也是可以的,在参数位置加一个true
sqlSessionFactory.openSession(true); //设置自动提交事务,这种情况不需要手动提交事务了
有时候可能需要返回主键的值,可以这样写SQL语句
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
在 insert 标签上添加如下属性:
useGeneratedKeys:是够获取自动增长的主键值。true表示获取keyProperty :指定将获取到的主键值封装到哪儿个属性里
修改
eg1:
*set* 标签可以用于动态包含需要更新的列,忽略其它不更新的列。
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName != ''">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName != ''">
company_name = #{companyName},
</if>
<if test="ordered != null">
ordered = #{ordered},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
</set>
where id = #{id};
</update>
删除
eg1:删除一行
<delete id="deleteById">
delete from tb_brand where id = #{id};
</delete>
eg2:批量删除
也就是将删除的行数以数组的形式告诉
foreach 标签
用来迭代任何可迭代的对象(如数组,集合)。
- collection 属性:
- mybatis会将数组参数,封装为一个Map集合。
- 默认:array = 数组
- 使用@Param注解改变map集合的默认key的名称
- mybatis会将数组参数,封装为一个Map集合。
- item 属性:本次迭代获取到的元素。
- separator 属性:集合项迭代之间的分隔符。
foreach
标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。 - open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次
- close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
<delete id="deleteByIds">
delete from tb_brand where id
in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
;
</delete>
后面还有一个参数传递,建议是啥都用@param()形式给出,避免报错。
还有一个SQL注解开发,建议是上面的学会就行,这个学不学都差不多,毕竟难的学会了,这简单的自然不在话下。