Mybatis学习笔记
简介
初始jdbc操作的分析 |
---|
1.数据库连接创建、释放频繁导致资源浪费 |
2.sql语句的变动需要改变java代码(耦合度高) |
3.查询操作,需要手动将结果集的数据(rs)封装到实体中,同理插入操作也要手动设置实体数据到sql语句中的占位符(?,?) |
解决方案 |
---|
使用数据库连接池初始化连接资源 |
将sql语句抽取到xml配置文件中 |
使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射 |
Mybatis就是这样一种优秀的java持久层框架,内部封装了jdbc开使得发者只需要关注sql语句本身,而不用去加载驱动、创建连接。
它通过xml或者注解方式将要执行的statement配置起来,将java对象和sql的动态参数映射生成最终执行的sql语句。最后将结果集映射为java对象返回,采用了ORM思想解决实体和数据库映射的问题。
配置
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>
<!--加载外部配置文件-->
<properties resource="jdbc.properties"/>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.domain.User" alias="user"/>
</typeAliases>
<!--数据源环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<!--加载映射文件-->
<mappers>
<mapper resource="com\mapper\UserMapper.xml"/>
</mappers>
</configuration>
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 namespace="userMapper">
<!--删除操作-->
<delete id="delete" parameterType="int">
delete from user where id =#{id}
</delete>
<!--修改操作-->
<update id="update" parameterType="user">
update user set username=#{username},password=#{password} where id=#{id}
</update>
<!--插入操作-->
<insert id="save" parameterType="user">
insert into user values(#{id},#{username},#{password})
</insert>
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
Mybatis相应API
- 通过加载mybatis核心文件的输入流形式构建一个SqlSessionFactory对象
//获得核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
/**
* openSession:默认开启事务,需要手动提交事务
* openSession(Boolean autoCommit):参数为是否自动提交
*/
//执行操作 参数:namespace+id
List<User> userList = sqlSession.selectList("userMapper.findAll");
//打印资源
System.out.println(userList);
//释放资源
sqlSession.close();
Dao层的实现
- 传统开发方式
- 代理开发方式:
- Mapper.xml文件中的命名空间(namespace)和mapper接口的全限定名相同
- 接口方法名和mapper.xml中每个statement的id相同
- 接口的输入输出参数要与parameterType以及resultType类型相同
UserMapper.xml
<mapper namespace="com.dao.UserMapper">
<!--查询操作-->
<select id="findAll" resultType="user">
select * from user
</select>
<!--根据id查询-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id=#{id}
</select>
</mapper>
UserMapper
public interface UserMapper {
public List<User> findAll() throws IOException;
public User findById(int id);
}
Test
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAll();
System.out.println(all);
User user = mapper.findById(1);
System.out.println(user);
}
动态Sql语句
public List<User> findByCondition(User user);
<select id="findByCondition" parameterType="user" resultType="user">
select * from user(/*这里不加where标签,可以写where 1=1 完成拼接*/)
<where>
<if test="id!=0">
and id=#{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
<if test="password!=null">
and password=#{password}
</if>
</where>
</select>
public List<User> findByIds(List<Integer> ids);
<select id="findByIds" parameterType="list" resultType="user">
select * from user
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
resultType:注意如果返回的是集合,那传出参数应该设置为集合包含的类型,而不是集合本身。 传入参数paramterType的话就不用管 正常传入就行
sql语句抽取
<!--sql语句的抽取,用sql标签就行-->
<sql id="selectUser">select * from user</sql>
<!--include标签 把抽取的id设置上去-->
<include refid="selectUser"/>
MyBatis核心配置文件
- properties标签:加载外部配置文件
- typeAliases标签:设置类型别名
- environments标签:数据源配置标签
- typeHandler标签:配置自定义类型处理器
- plugins标签:配置MyBatis插件(比如分页插件)
<!--加载外部配置文件-->
<properties resource="jdbc.properties"/>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.domain.User" alias="user"/>
</typeAliases>
<!--注册类型处理器-->
<typeHandlers>
<typeHandler handler="com.handler.DateTypeHandler"/>
</typeHandlers>
<!--配置分页助手插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
<!--数据源环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<!--加载映射文件-->
<mappers>
<mapper resource="com\mapper\UserMapper.xml"/>
</mappers>
MyBatis多表操作
一对一
<resultMap id="orderMap" type="order">
<!--手动指定字段与实体属性的映射关系
column:数据表的字段名称
property:实体的属性名称
-->
<id column="oid" property="id"/>
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
<!-- <result column="uid" property="user.id"/>-->
<!-- <result column="username" property="user.username"/>-->
<!-- <result column="password" property="user.password"/>-->
<!-- <result column="birthday" property="user.birthday"/>-->
<!--
上面注释换种写法可以写成如下:
property:当前实体中(order)的属性名称(private User user)
javaType:当前实体(order)中的属性类型(User)
-->
<association property="user" javaType="user">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
<select id="findAll" resultMap="orderMap">
select * ,o.id oid from orders o, user u where o.uid=u.id
</select>
一对多 多对多
resultMap和collection标签
<resultMap id="userMap" type="user">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<!--配置集合信息
property:集合名称
ofType:当前集合中的数据类型
-->
<collection property="orderList" ofType="order">
<!--封装order的数据-->
<id column="oid" property="id"/>
<result column="ordertime" property="ordertime"/>
<result column="total" property="total"/>
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select *,o.id oid from user u,orders o where u.id=o.uid
</select>
<resultMap id="userRoleMap" type="user">
<!--封装user信息-->
<id column="userid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
<!--user内部Role的信息-->
<collection property="roleList" ofType="role">
<id column="roleid" property="id"/>
<result column="rolename" property="rolename"/>
<result column="roleDesc" property="roleDesc"/>
</collection>
</resultMap>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
select * from user u,sys_user_role ur,sys_role r where u.id=ur.userid and ur.roleid=r.id
</select>
column="roleid" property="id"/>
<result column="rolename" property="rolename"/>
<result column="roleDesc" property="roleDesc"/>
</collection>
</resultMap>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
select * from user u,sys_user_role ur,sys_role r where u.id=ur.userid and ur.roleid=r.id
</select>