1.MyBatis介绍
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
与 JDBC 相比, MyBatis 简化 了相关代码, SQL 语句在一行代码中就能执行 。 MyBatis 提供了一个映射引擎 , 声明式地将 SQL 语句的执行结果与对象树映射起来。通过使用 一种内建的类XML 表达式语言, SQL 语句可以被动态生成。
与Hibernate相比,Hibernate屏蔽了SQL,只能全表映射。无法根据不同的条件组装不同的SQL,对多表关联和复杂SQL查询支持较差,需要自己写SQL,返回后,需要自己将数据组装为POJO。且不能有效支持存储过程。
MyBatis 支持声明式数据缓存( declarative data caching ) 。当 一条 SQL 语句被标记为“可缓存”后,首次执行它时从数据库获取的所有数据会被存储在高速缓存中,后面再执行这条语句时就会从高速缓存中读取结果,而不是再次命中数据库 。 MyBatis 提供了默认情况下基于 Java HashMap 的缓存实现,以及用于与 OS Cache 、 Ehcache 、 Hazeleast 和 Memcached 连接的默认连接器,同时还提供了 API 供其他缓存实现使用。
2. 在实体类中不要使用基本类型 。 基本类型包括 byte 、 int , short 、 long 、 float 、double 、 char 、 boolean。
MyBatis 使用 Java 的动态代理可以直接通过接口来调用 相应 的方法,不需要提供接口的实现类,更不需要在实现类中使用 SqlSession以通过命名空 间间接调用 。 另外,当有多个参数的时候,通过参数注解@Param 设置参数的名字省去了手动构造 Map 参数的过程,尤其在 Spring 中使用的时候,可以配置为自动扫描所有的接口类 ,直接将接口注入需要用到的地方。
注意:
- 当 Mapper 接口和 XML 文件关联的时候,命名空间口amespace 的值就需要配置成接口的全限定名称。
- XML 中的 select 标签的 id 属性值和定义的接口方法名是一样的 ρMyBatis就是通过这种方式将接口方法和 XML 中定义的SQL 语句关联到一起的,如果接口方法没有和XML 中的 id 属性值相对应,启动程序便会报错。
- 接口中定义的返回值类型必须和XML 中配置的 resultType 类型一致,否则就会因为类型不一致而抛出异常。返回值类型是由 XML 中的 resultType (或 resultMap 中的 type )决定的,不是由接口中写的返回值类型决定的。
- 如果使用 result Type 来设置返回结果的类型,需要在 SQL 中为所有列名和属性名不一致的列设置别名,通过设置别名使最终的查询结果列和 resultType 指定对象(即实体类)的属性名保持一致,进而实现自动映射。
3. MyBatis 提供 了 一个全局属性mapUnderscoreToCamelCase ,通过配置这个属性为 true 可以自动将以下画线方式命名的数据库列映射到 Java 对象的驼峰式命名属性中,这个属性默认为 false。如:
<settings>
〈!--其它配置 --〉
<setting name=” mapUnderscoreToCamelCase” value=”true ” />
</settings>
使用上述配置的时候,前面的 selectAll 可以改写如下 。
<select id= ” selectAll ” resultType=” tk.mybatis.simple.model.SysUser” >
select_id,user_name ,user_password,user_email ,user_info,head_img,create_time
from sys_user
</select>
而无需写成:
<select id=” selectAll ” resultType=”t k.mybatis.simple.model . SysUser” >
select id,
user_name userName,
user_password userPassword ,
user_email userEmail,
user_info userinfo ,
head_img headimg,
create_time createTime
from sys_user
</select>
BLOB 对应的类型是 ByteArrayinputStream ,就是二进制数据流 。由于数据库区分 date 、 time 、 datetime 类型,但是 Java 中一般都使用 j ava.util. Date类型 。 因此为了保证数据类型的正确,需要手动指定日期类型, date 、 time 、 date t ime 对应的 JDBC 类型分别为 DATE 、 TIME 、 TIMESTAMP 。
使用< selectKey>标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。而useGeneratedKeys这种回写主键的方法只适用于支持主键自增的数据库。
4. 接口参数
对于参数比较少的情况 ,有两种方式可以采用:使用 Map 类型作为参数或使用@ Param 注解。因为第一种方式需要自己手动创建 Map 以及对参数进行赋值,这样并不简洁,所以推荐使用@ Param 注解。
给参数配置@ Param 注解后, MyBatis 就会自动将参数封装成 Map 类型,@ Param 注解值会作为 Map 中的 key,因此在 SQL 部分就可以通过配置的注解值来使用参数。具体使用如下:
List<SysRole> selectRolesByUserAndRole(
@Param (” user ”) SysUser user,
@Param (” role ”) SysRole role );
当参数类型是一些 JavaBean 的时候,用法略有不同。如下将接口方法中的参数换成 JavaBean 类型:
List<SysRole> selectRolesByUserAndRole(
@Param (” user ”) SysUser user,
@Param (” role ”) SysRole role );
这时,在 XML 中就不能直接使用#{ userid }和#{ enabled }了,而是要通过点取值方式使用#{ user.id }和#{ role . enabled } 从两个 JavaBean 中取出指定属性的值 。
5. Mybatis动态SQL
MyBatis 的动态 SQL 在 XML 中支持的几种标签:
- if
- choose ( when、otherwise)
- trim(where、set)
- foreach
- bind
1)if
if标签通常用于 WHERE 语句中,通过判断参数值来决定是否使用某个查询条件,它也经常用于 UPDATE 语句中判断是否更新某一个字段 , 还可以在 INSERT 语句中用来判断是否插入某个字段的值。如:
<select id=”selectByUser” resultType=” tk.mybatis.simple.model.SysUser” >
select id,
user_name userName ,
user_password userPassword ,
user_email userEmail ,
user_info userinfo ,
head_img headimg ,
create_time createTime
from sys_user
where 1 = 1
<if test=” userName != null and userName != ''”>
and user name like concat (’%’,#{userName}, ’%’ )
</if>
<if test=” userEmail != null and userEmail !='' ” >
and user email = #{userEmail}
〈/if>
</select>
注意:if 标签有一个必填的属性 test, test 的属性值是一个符合 OGNL 要求的判断表达式,表达式的结果可以是 true 或 false ,除此之外所有的非0值都为 true ,只有0为 false 。 为了方便理解,在表达式中 ,建议只用 true 或 false 作为结果 。
2)choose
if 标签提供了基本的条件判断,但是它无法实现 if. . . else 、 if ... else ...的逻辑,要想实现这样的逻辑,就需要用到 choose when otherwise 标签。 choose 元素中包含 when和 otherwise 两个标签,一个 choose 中至少有一个 when ,有 0 个或者1个otherwise。如:
<select id=”selectByidOrUserName” resultType=” tk.mybatis.simple.model.SysUser” >
select id,
user_name userName , user_password userPassword , user_email userEmail ,
user_info userinfo , head_img headimg , create_time createTime
from sys_ user
where 1 = 1
<choose>
<when test=” id != null ” >
and id= #{id}
</when >
<when test=” userName != null and userName !='' ”>
and user_name = #{userName}
</when>
<otherwise>
and 1 = 2
</otherwise>
</choose>
</select>
3)where
where 标签的作用:如果该标签包含的元素中有返回值,就插入一个 where ;如果 where后面的字符串是以 AND 和 OR 开头的,就将它们剔除。如:
<select id=” selectByUser” resultType=” tk.mybatis.simple.model.SysUser” >
select id,
user_name userName,
user_password userPassword ,
user_email userEmail ,
user_info userinfo ,
head_img headimg,
create_time createTime
from sys_user
<where>
<if test=”userName != null and userName !='' ”>
and user_name like concat ( ’%’,#{userName}, ’%’)
</if>
<if test=” userEmail ! = '' and userEmail != null ”>
and user_email = #{userEmail}
</if>
</where>
</select >
4)set
set 标签的作用:如果该标签包含的元素中有返回值,就插入一个 set :如果 set 后面的字符串是 以逗号结尾的,就将这个逗号剔除 。
<update id=”updateByidSelective ” >
update sys_user
<set>
<if test=”userName != null and userName !='' ”>
user_name= #{userName} ,
</if>
<if test=” userPassword != null and userPassword ! = '' ”>
user_password= #{userPassword} ,
</if>
<if test=”userEmail != null and userEmail != '' ”>
user_email = #{userEmail} ,
</if>
<if test=” userinfo != null and userinfo !='' ”>
user_info = #{userinfo},
</if>
<if test=”headimg != null ” >
head_img = #{headimg, jdbcType=BLOB},
</if>
<if test=”createTime != null ”>
create_time = #{createTime, jdbcType=TIMESTAMP},
</if>
id = # {id} ,
</set>
where id = #{id}
</update>
5)trim
where 和 set 标签 的功能都可以用 trim 标签来实现,并且在底层就是通过TrimSqlNode 实现的 。where 标签对应 trim 的实现如下:
<trim prefix=”WHERE ” prefixOverrides=”AND IOR ” >
</ trim>
set 标签对应 的 trim 实现如下 :
<trim suffix=” SET” suffixOverrides=”, ” >
</ trim
trim 标签有如下属性:
prefix :当 trim 元素内包含内容时,会给内容增加 prefix 指定的前缀。
prefixOverrides :当 trim 元素内包含内容时,会把内容中匹配的前缀字符串去掉。
suffix :当 trim 元素内包含内容时,会给内容增加 suffix 指定的后缀。
suffixOverrides :当 trim 元素内包含内容时,会把内容中匹配的后缀字符串去掉。
6)foreach
SQL 语句中有时会使用 IN 关键字,例如 id in ( 1 , 2 , 3 )。可以使用${ ids }方式直接获取值,但这种写法不能防止 SQL 注入,想避免 SQL 注入就需要用#{}的方式,这时就要配合使用 foreach 标签来满足需求。
foreach 可以对数组、 Map 或实现了iterable 接口(如 List 、 Set )的对象进行遍历。数组在处理时会转换为 List 对象,因此 foreach 遍历的对象可以分为两大类 : Iterable类型和 Map 类型。
7)bind
bind 标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中。使用 con cat 函数连接字符串,在 MySQL 中,这个函数支持多个参数,但在 Oracle 中只支持两个参数。由于不 同数据库之间的语法差异 ,如果更换数据库,有些 SQL 语句可能就需要重写。针对这种情况,可 以使用 bind 标签来避免由于更换数据库带来的一些麻烦。
原来的SQL:
<if test=” userName != null and userName ! = ''”>
and user_name like concat ( ’%’, #{userName},’%’ )
</if>
变更后:
<if test=” userName != null and userName !=''”>
<bind name= " userNameLike ” value = ”'%'+ userName + '%'” /〉
and user_name like #{userNameLike}
</if>
6. Mybatis开发基本步骤
1)创建基础配置文件SqlMapConfig.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>
<typeAliases>
<!-- 定义单个pojo类别名
type:类的全路劲名称
alias:别名
-->
<typeAlias type="com.mybatis.pojo.User" alias="User"/>
</typeAliases>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<mappers>
<!--
使用class属性引入接口的全路径名称:
使用规则:
1. 接口的名称和映射文件名称除扩展名外要完全相同
2. 接口和映射文件要放在同一个目录下
-->
<!-- <mapper class="cn.itheima.mapper.UserMapper"/> -->
<!-- 使用包扫描的方式批量引入Mapper接口
使用规则:
1. 接口的名称和映射文件名称除扩展名外要完全相同
2. 接口和映射文件要放在同一个目录下
-->
<!-- <package name="cn.itheima.mapper"/> -->
<mapper class="com.mybatis.mapper.UserMapper" />
</mappers>
</configuration>
此处的数据库连接配置可存在一个配置文件db.properties中:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
然后修改上面SqlMapConfig.xml相关配置,如下:
<!-- 定义外部数据库配置文件
db.properties
-->
<properties resource="db.properties"></properties>
<typeAliases>
<!-- 定义单个pojo类别名
type:类的全路劲名称
alias:别名
-->
<typeAlias type="com.mybatis.pojo.User" alias="User"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
2)创建实体类,如User.java;
Public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
get/set……
}
3)创建接口
public interface UserMapper {
public User findUserById(Integer id);
public List<User> findUserByUserName(String username);
}
3)创建映射文件,如UserMapper .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接口代理实现编写规则:
1. 映射文件中namespace要等于接口的全路径名称
2. 映射文件中sql语句id要等于接口的方法名称
3. 映射文件中传入参数类型要等于接口方法的传入参数类型
4. 映射文件中返回结果集类型要等于接口方法的返回值类型
-->
<mapper namespace="com.mybatis.mapper.UserMapper">
<!--
id:sql语句唯一标识
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}占位符:起到占位作用,如果传入的是基本类型,那么#{}中的变量名可以随意写
-->
<select id="findUserById" parameterType="int" resultType="User">
select * from user where id=#{id}
</select>
<!--
如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所以映射文件中应该配置成集合泛型的类型
${}拼接符:字符串原样拼接,如果传入的是基本数据类型,那么${}中的变量名必须使用value
注意:拼接符有sql注入的风险,所以慎重使用。一般=号后面用占位符,like后面用拼接符
-->
<select id="findUserByUserName" parameterType="string" resultType="User">
select * from user where username like '%${value}%'
</select>
</mapper>
4)测试类
public class UserMapperTest {
private SqlSessionFactory sqlSessionFactory;//会话工厂
//初始化
public void init() throws Exception{
String resource= "SqlMapConfig.xml";// 配置文件
InputStream inputStream = Resources.getResourceAsStream(resource); // 通过流将核心配置文件读取进来
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 通过核心配置文件输入流来创建会话工厂
}
public void testFindUserById() throws Exception {
// 通过工厂创建数据库会话实例sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(10);
System.out.println(user);
}
public void testFindUserByUserName() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> list = userMapper.findUserByUserName("王");
Iterator<User> iterator = list.iterator();
while (iterator.hasNext()) {
User user= iterator.next();
System.out.println(user.toString());
}
}
}
5)总结1:
(1)mybatis是一个持久层框架, 作用是跟数据库交互完成增删改查
(2)原生Dao实现(需要接口和实现类)
(3)动态代理方式(只需要接口)
mapper接口代理实现编写规则:
- 映射文件中namespace要等于接口的全路径名称
- 映射文件中sql语句id要等于接口的方法名称
- 映射文件中传入参数类型要等于接口方法的传入参数类型
- 映射文件中返回结果集类型要等于接口方法的返回值类型
(4) #{}占位符:占位
如果传入的是基本类型,那么#{}中的变量名称可以随意写
如果传入的参数是pojo类型,那么#{}中的变量名称必须是pojo中的属性.属性.属性...
(5) ${}拼接符:字符串原样拼接
如果传入的是基本类型,那么${}中的变量名必须是value
如果传入的参数是pojo类型,那么${}中的变量名称必须是pojo中的属性.属性.属性...
注意:使用拼接符有可能造成sql注入,在页面输入的时候可以加入校验,不可输入sql关键字,不可输入空格
(6)映射文件:
- 传入参数类型通过parameterType属性指定
- 返回结果集类型通过resultType属性指定
(7)hibernate和mybatis区别:
hibernate:它是一个标准的orm框架,比较重量级,学习成本高.
优点:高度封装,使用起来不用写sql,开发的时候,会减低开发周期.
缺点:sql语句无法优化
应用场景:oa(办公自动化系统), erp(企业的流程系统)等,还有一些政府项目,
总的来说,在用于量不大,并发量小的时候使用.
mybatis:它不是一个orm框架, 它是对jdbc的轻量级封装, 学习成本低,比较简单
有点:学习成本低, sql语句可以优化, 执行效率高,速度快
缺点:编码量较大,会拖慢开发周期
应用场景: 互联网项目,比如电商,P2p等
总的来说是用户量较大,并发高的项目.
7. 动态SQL扩展
1) 在接口映射文件如上面的UserMapper .xml,使用where if 时,可如下将通用的sql封装,即:
<mapper namespace="cn.itheima.mapper.UserMapper">
<!-- 封装sql条件,封装后可以重用.
id:是这个sql条件的唯一标识 -->
<sql id="user_Where">
<!-- where标签作用:
会自动向sql语句中添加where关键字
会去掉第一个条件的and关键字
-->
<where>
<if test="username != null and username != ''">
and username like '%${username}%'
</if>
<if test="sex != null and sex != ''">
and sex=#{sex}
</if>
</where>
</sql>
<select id="findUserByUserNameAndSex" parameterType="cn.itheima.pojo.User" resultType="cn.itheima.pojo.User">
select * from user
<!-- 调用sql条件 refid参数值为封装sql条件的id-->
<include refid="user_Where"></include>
</select>
</mapper>
2)在接口映射文件如上面的UserMapper .xml,使用foreach,如下:
<select id="findUserByIds" parameterType="com.mybatis.pojo.QueryVo" resultType="User">
select * from user
<where>
<if test="ids != null">
<!--
foreach:循环传入的集合参数
collection:传入的集合的变量名称
item:每次循环将循环出的数据放入这个变量中
open:循环开始拼接的字符串
close:循环结束拼接的字符串
separator:循环中拼接的分隔符
-->
<foreach collection="ids" item="id" open="id in (" close=")" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
其中:在com.mybatis.pojo.QueryVo这个类中定义了一个List集合ids用于存储id,即private List<Integer> ids;
8. 单个对象的映射关系(即一对一的关系)
有两种方式:
1)自动映射:在接口映射文件如上面的UserMapper .xml中如下配置:
<!-- 一对一:自动映射 -->
<select id="findOrdersAndUser1" resultType="cn.itheima.pojo.CustomOrders">
select a.*, b.id uid, username, birthday, sex, address
from orders a, user b
where a.user_id = b.id
</select>
order表的实体类如下:
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
get...
set...
}
其中cn.itheima.pojo.CustomOrders这个类是一个继承类,继承了orders表实体类,并包含user表的字段。因为java是单继承,所以不推荐使用该方式。
2)手动映射:在接口映射文件如上面的UserMapper .xml中如下配置:
<!-- 一对一:手动映射 -->
<!--
id:resultMap的唯一标识
type:将查询出的数据放入这个指定的对象中
注意:手动映射需要指定数据库中表的字段名与java中pojo类的属性名称的对应关系
-->
<resultMap type="cn.itheima.pojo.Orders" id="orderAndUserResultMap">
<!-- id标签指定主键字段对应关系
column:列,数据库中的字段名称
property:属性,java中pojo中的属性名称
-->
<id column="id" property="id"/>
<!-- result:标签指定非主键字段的对应关系 -->
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 这个标签指定单个对象的对应关系
property:指定将数据放入Orders中的user属性中
javaType:user属性的类型
-->
<association property="user" javaType="cn.itheima.pojo.User">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findOrdersAndUser2" resultMap="orderAndUserResultMap">
select a.*, b.id uid, username, birthday, sex, address
from orders a, user b
where a.user_id = b.id
</select>
此种方式在定义orders表的实体类时,需要定义user表的实体类对象,即定义一个字段 private User user; 然后使用get和set方式取值和赋值。
9. 对集合对象的映射(即一对多的关系)
在接口映射文件如上面的UserMapper .xml中如下配置:
<resultMap type="cn.itheima.pojo.User" id="userAndOrdersResultMap">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 指定对应的集合对象关系映射
property:将数据放入User对象中的ordersList属性中
ofType:指定ordersList属性的泛型类型
-->
<collection property="ordersList" ofType="cn.itheima.pojo.Orders">
<id column="oid" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
</collection>
</resultMap>
<select id="findUserAndOrders" resultMap="userAndOrdersResultMap">
select a.*, b.id oid ,user_id, number, createtime
from user a, orders b where a.id = b.user_id
</select>
这种映射关系在user表的实体类中需要包含orders表的实体对象集合,即定义一个字段为 private List<Orders> ordersList;然后使用get和set方式取值和赋值。
10. Spring 与 Mybatis整合
1)整合需要的*.jar包可在:mybatis与spring整合全部jar包(包括springmvc) 进行下载。
2)整合后的核心配置文件ApplicationContext.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!-- 整合会话工厂归spring管理 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis核心配置文件 -->
<property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
<!-- 指定会话工厂使用的数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--实现方式一: 配置原生Dao实现
注意:class必须指定Dao实现的全路径名称
-->
<!-- <bean id="userDao" class="com.sm.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
-->
<!-- 实现方式二: Mappper接口代理实现
-->
<!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.sm.mapper.UserMapper1"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean> -->
<!-- 使用包扫描的方式批量引入Mapper
扫描后引用的时候可以使用类名,首字母小写.
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定要扫描的包的全路径名称,如果有多个包用英文状态下的逗号分隔 -->
<property name="basePackage" value="com.sm.mapper"></property>
</bean>
</beans>
3)mybatis的核心配置文件SqlMapConfig.xml就不需要了
4)假如采用的是原生DAO来实现的话,实现类需要进行修改(需继承一个超类SqlSessionDaoSupport), 如下(我在项目中没有采用这种方式,):
package com.sm.dao;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import com.sm.pojo.User;
/**
* 整合之后实现类需要继承一个超类SqlSessionDaoSupport
* 之后获取会话直接用this.getSqlSession()
* @author xudso
*
*/
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User findUserById(Integer id){
SqlSession sqlSession = this.getSqlSession();
User user=sqlSession.selectOne("test.findUserById",id);
return user;
}
@Override
public List<User> findUserByUserName(String userName) {
SqlSession sqlSession = this.getSqlSession();
List<User> list = sqlSession.selectList("test.findUserByUserName", userName);
return list;
}
@Override
public void insertUser(User user) {
SqlSession sqlSession = this.getSqlSession();
sqlSession.insert("test.insertUser", user);
sqlSession.commit();
}
@Override
public void deletUserById(Integer id) {
SqlSession sqlSession = this.getSqlSession();
sqlSession.delete("test.delUser", id);
sqlSession.commit();
}
@Override
public void updateUserById(User user) {
SqlSession sqlSession = this.getSqlSession();
sqlSession.update("test.updateUser", user);
sqlSession.commit();
}
}
5)采用Mappper接口代理实现的方式(推荐这种方式),即接口类UserMapper1.java和接口映射文件UserMapper1.xml分别如下:
package com.sm.mapper;
import java.util.List;
import com.sm.dao.UserDao;
import com.sm.pojo.QueryVo;
import com.sm.pojo.User;
public interface UserMapper1 {
public User findUserById(Integer id);
public List<User> findUserByUserName(String username);
public List<User> findUserByVo(QueryVo queryVo);
public List<User> findUserByIds(QueryVo queryVo);
}
<?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接口代理实现编写规则:
1. 映射文件中namespace要等于接口的全路径名称
2. 映射文件中sql语句id要等于接口的方法名称
3. 映射文件中传入参数类型要等于接口方法的传入参数类型
4. 映射文件中返回结果集类型要等于接口方法的返回值类型
-->
<mapper namespace="com.sm.mapper.UserMapper1">
<!--
id:sql语句唯一标识
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}占位符:起到占位作用,如果传入的是基本类型,那么#{}中的变量名可以随意写
-->
<select id="findUserById" parameterType="int" resultType="com.sm.pojo.User">
select * from user where id=#{id}
</select>
<!--
如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所以映射文件中应该配置成集合泛型的类型
${}拼接符:字符串原样拼接,如果传入的是基本数据类型,那么${}中的变量名必须使用value
注意:拼接符有sql注入的风险,所以慎重使用。一般=号后面用占位符,like后面用拼接符
-->
<select id="findUserByUserName" parameterType="string" resultType="com.sm.pojo.User">
select * from user where username like '%${value}%'
</select>
<select id="findUserByVo" parameterType="com.sm.pojo.QueryVo" resultType="com.sm.pojo.User">
select * from user where username like '%${user.username}%' and sex=#{user.sex}
</select>
<select id="findUserByIds" parameterType="com.sm.pojo.QueryVo" resultType="com.sm.pojo.User">
select * from user
<where>
<if test="ids != null">
<!--
foreach:循环传入的集合参数
collection:传入的集合的变量名称
item:每次循环将循环出的数据放入这个变量中
open:循环开始拼接的字符串
close:循环结束拼接的字符串
separator:循环中拼接的分隔符
-->
<foreach collection="ids" item="id" open="id in (" close=")" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
</mapper>
5 )编写测试类(这里以 采用Mappper接口代理实现的方式编写测试类):
package com.sm.test;
import javax.jws.soap.SOAPBinding.Use;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sm.mapper.UserMapper1;
import com.sm.pojo.User;
public class UserMapperTest {
private ApplicationContext applicationContext;
//初始化
@Before
public void setUp() throws Exception{
String configLocation = "ApplicationContext.xml";
applicationContext = new ClassPathXmlApplicationContext(configLocation);
}
@Test
public void testFindUserById() throws Exception{
UserMapper1 userMapper1 =(UserMapper1) applicationContext.getBean("userMapper1");
User user =userMapper1.findUserById(1);
System.out.println(user);
}
}
11. 逆向工程
1)导入相应的包,可从这里现在:mybatis逆向工程自动生成需要的包
2)配置文件generator.xml(根据自己的需要进行修改)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root"
password="root">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection> -->
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="com.sm.pojo"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.sm.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.sm.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<!-- <table tableName="items"></table> -->
<table tableName="orders"></table>
<!-- <table tableName="orderdetail"></table> -->
<table tableName="user"></table>
<!-- <table schema="" tableName="sys_user"></table>
<table schema="" tableName="sys_role"></table>
<table schema="" tableName="sys_permission"></table>
<table schema="" tableName="sys_user_role"></table>
<table schema="" tableName="sys_role_permission"></table> -->
<!-- 有些表的字段需要指定java类型
<table schema="" tableName="">
<columnOverride column="" javaType="" />
</table> -->
</context>
</generatorConfiguration>
3)启动类StartServer.java。然后运行启动类就会自动生成表的实体类和对应的接口映射文件。
package generator;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
public class StartServer {
public void generator() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
try {
StartServer startServer = new StartServer();
startServer.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
12. 总结2:
1)输入映射(就是映射文件中可以传入哪些参数类型)
- 基本类型
- pojo类型
- Vo类型
2)输出映射(返回的结果集可以有哪些类型)
- 基本类型
- pojo类型
- List类型
3)动态sql:动态的拼接sql语句,因为sql中where条件有可能多也有可能少
- where:可以自动添加where关键字,还可以去掉第一个条件的and关键字
- if:判断传入的参数是否为空
- foreach:循环遍历传入的集合参数
- sql:封装查询条件,以达到重用的目的
4)对单个对象的映射关系:
- 自动关联(偷懒的办法):可以自定义一个大而全的pojo类,然后自动映射其实是根据数据库总的字段名称和pojo中的属性名称对应。
- 手动关联: 需要指定数据库中表的字段名称和java的pojo类中的属性名称的对应关系;使用association标签。
5)对集合对象的映射关系
只能使用手动映射:指定表中字段名称和pojo中属性名称的对应关系;使用collection标签。
6)spring和mybatis整合
整合后会话工厂都归spring管理
方式1:原生Dao实现:
- 需要在spring配置文件中指定dao实现类
- dao实现类需要继承SqlSessionDaoSupport超类
- 在dao实现类中不要手动关闭会话,不要自己提交事务.
方式2:Mapper接口代理实现:
在spring配置文件中可以使用包扫描的方式,一次性的将所有mapper加载
7)逆向工程:自动生成Pojo类,还可以自动生成Mapper接口和映射文件
注意:生成的方式是追加而不是覆盖,所以不可以重复生成,重复生成的文件有问题。如果想重复生成将原来生成的文件删除。