- mybatis和hibernate的比较
2)mybatis是首先创建一个PO实体对象,这点一样,然后是配置该对象的映射关系文件UserMapper.xml,里面配置实体对象与表字段之间的对应关系,这点也一样,但是mybatis是没有hibernate那种需要配置各种对象与对象之间关系的映射配置,最后是核心配置文件sqlMapConfig.xml和SqlSessionFactory获取SqlSession。
- 核心配置文件
<!-- mybatis提供环境切换配置,即不同环境可以选择不同的配置 如开发环境选development 线上环境选deploy -->
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!--支持两种事务管理 JDBC/MANAGED(mybatis不予管理,自主管理,即交给有事务容器的框架管理)-->
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC"/>
<!-- 数据库连接池 POOLED/UNPOOLED/JNDI 前两种就是说是否要使用连接池。最后一个是JNDI,这里简单说一下JNDI的概念。
JNDI可以屏蔽底层数据库,它是自己模拟出一个服务器然后给应用服务器提供一个url去连接到数据库,url与底层数据库没有关系,
不管是MySQL还是Oracle甚至Access都是一样的。这样做有个好处就是防止别人知道底层数据库,同时使用url能加密对数据库的访问。
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?charsetEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
- Mapper映射文件
<select id="findAll" resultType="domain.User">
SELECT * FROM sys_user
</select>
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
另外一个是selectList,底层究竟是怎么把ResultSet封装到一个List中的。主要就是在ResultSet中获取到值时,通过反射知道每个对象的属性,然后就根据属性set对应的值,当然这里必须保证对象属性名和表字段名一样,否则是无法自动映射的。比如,映射menu_id到menuId是无法自动映射的,但是mybatis这里有一个配置可以开启驼峰命名的自动映射,也就是说只要符合aaa_bb映射到aaaBb这种写法的,也可以自动映射,但是需要手动配置开启。mapUnderscoreToCamelCase这是配置的name。<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
- mybatis不能自动映射的解决办法
<!--中介作用,实现自定义表与对象字段的映射-->
<resultMap id="BaseResultMap" type="domain.User">
<!--主键映射-->
<id column="id" property="id" jdbcType="INTEGER"/>
<!--字段映射-->
<result column="user_name" property="username" jdbcType="VARCHAR"/>
<!--关系映射-->
</resultMap>
- mybatis提供的简化操作
<!-- 类型别名替换 -->
<typeAliases>
<!--type:类型全路径 alias:别名-->
<typeAlias type="domain.User" alias="user"/>
<!-- 包扫描的方式 ,里面所有类都能使用别名,别名就是类名,且不区分大小写-->
<package name="com.me.pojo"/>
</typeAliases>
- 动态SQL使用
<!--传入参数为map,即代表传入参数可以任意指定要传入的key-value。但有时候要查询的参数不一定全有,所以需要动态确定是否查询该参数-->
<select id="findByNameAndSex" parameterType="map" resultType="domain.User">
SELECT * FROM sys_user
<where>
<if test="name != null">username LIKE #{name}</if>
<if test="sex != null">and sex = #{sex}</if>
</where>
</select>
<!--更新时,有时要更新的参数不是全部都修改,所以也要动态控制-->
<update id="update" parameterType="domain.User">
UPDATE sys_user
<set>
<if test="username != null">username = #{username},</if>
<if test="sex != null">sex = #{sex},</if>
<if test="birthday != null">birthday = #{birthday},</if>
<if test="address != null">address = #{address}</if>
</set>
where id = #{id}
</update>
<select id="findIn" parameterType="int" resultType="domain.User">
SELECT * FROM sys_user
WHERE id IN
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
特殊字符处理
<!--特殊字符处理-->
<select id="findById" parameterType="map" resultType="domain.User">
SELECT * FROM sys_user
WHERE id > #{idStart} AND id <![CDATA[<]]> #{idEnd}
</select>
- #{}与${}的区别
#{}相当于PreStatement,即预编译SQL,它运行的SQL是有一个占位符,传入的参数如果是字符串会自动在两边加上引号,即 'xiaomin' ,好处是可以防止SQL注入。
${}相当于Statement,它会把参数与SQL拼接成字符串去查询,而不是使用占位符,这种方式的好处就是比较灵活,例如order by 查询时,可以手动传入要不要order by,但坏处就是可以SQL注入。
- jdbcType使用
- 对一关系映射配置
mybatis与hibernate不同,它只有两种对象关系映射,即对一和对多,并且做法也与hibernate很不同,hibernate是配置关系后自动生成查询SQL,而mybatis即使配置了对象关系,依然要自己去写查询子对象的SQL,配置对象关系的唯一作用就是在SQL查询出来后帮助映射的。这里先说对一的关系映射。
<resultMap id="BaseResultMap" type="domain.User">
<!--主键映射 property对应对象属性 column对应数据库字段名-->
<id column="id" property="id" jdbcType="INTEGER"/>
<!--普通字段映射-->
<result column="username" property="username" jdbcType="VARCHAR"/>
<!--对象关系映射 在mybatis里只有对一和对多两种关系映射-->
<!--association是 对一 关系映射-->
<association property="userInfo" javaType="domain.UserInfo">
<id property="id" column="id" />
<result property="station" column="station"/>
<result property="joinDate" column="join_date"/>
</association>
</resultMap>
对一的关系映射使用association标签,在里面配置当前对象的子对象,以及子对象要映射的详细字段。配置好后进行测试,发现子对象只有UserInfo的id有值,其实这个很好相同,因为User与userinfo都是用id作为主键且都叫id,mybatis的映射原理本来就是靠SQL的结果集,发现userinfo有个id字段,结果集也有id的字段,刚好匹配,至于为什么只有id有值,是因为我们查询的时候只写了查询user信息的SQL,下面用SQL连接两张表进行查询。
<select id="findUserInfo" resultMap="UserInfoRM">
SELECT u.id, u.username, u.birthday, u.sex, u.address, i.id, i.station, i.join_date FROM
(SELECT * FROM sys_user) u
LEFT JOIN
(SELECT * FROM user_info) i
ON u.id = i.id
</select>
<resultMap id="UserInfoRM" type="domain.User" extends="UserRM">
<!--对一使用javaType,表示要映射的这个对象是什么类型的-->
<association property="userInfo" javaType="domain.UserInfo">
<id property="id" column="user_info_id" />
<result property="station" column="station"/>
<result property="joinDate" column="join_date"/>
</association>
</resultMap>
- 对多关系映射配置
<resultMap id="UserInfoBookRM" type="domain.User" extends="UserInfoRM">
<!--对多使用ofType,表示要映射的这个集合中的元素是什么类型的-->
<collection property="books" ofType="domain.Book">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="money" column="money"/>
</collection>
</resultMap>
查询的SQL如下:
SELECT
ui.*, b.id AS book_id,
b. NAME,
b.money
FROM
(
SELECT
u.*, i.id AS user_info_id,
i.station,
i.join_date
FROM
(SELECT * FROM sys_user) u
LEFT JOIN (SELECT * FROM user_info) i ON u.id = i.id
) ui
LEFT JOIN (SELECT * FROM book) b ON ui.id = b.user_id

SELECT
*
FROM
sys_user u
LEFT JOIN user_info i ON u.id = i.id
LEFT JOIN book b ON u.id = b.user_id
WHERE
u.id = 1
这种写法与上面那条SQL最后加where条件过滤效果一样,但是,这条是没办法优化的,因为它是先把三张表的所有数据连接起来,再进行过滤的,如果数据量很大的话,性能是很低的。这种查询所有数据然后再过滤的做法其实跟视图类似,都是查询表中的所有数据,如果有多张表就都查出来,最后连在一起,这样的性能可想而知,所以一般大型项目中时禁用视图的,就是因为它要查询表中的所有数据。从这里又能想到mybatis与hibernate的差异了,要查询对象间的映射关系,hibernate其实就是采用这种简单粗暴的办法,项目数据量变大时根本没办法优化SQL,因为它的SQL都是自动生成的,而这里如果是mybatis就大不一样了,像上面那条SQL,如果在查第一张表的时候就加上过滤条件,就不用查很多数据了,SQL的性能就能得到提升,所以这也算是mybatis相对hibernate一个很大的优势吧。