什么是Mybatis
Mybatis是有个持久层的ORM框架,简化了JDBC的操作,让我们只专注与sql语句的拼装,其他复杂的过程交给Mybatis去完成。Mybatis是apache一个开源的项目ibatis,2010年迁移到了Google code上,2013年11月迁移到Git Hub上。
Mybatis框架在市面上应用广泛,他像其他的框架一样,都有一个核心的配置文件,还有每个接口的sql关系映射文件,通过new SqlSessionFactoryBuilder().builder(Resources.getResourceAsStream(“mybatis-config.xml”)),生成SqlSessionFactory对象,进而生成SqlSession对象,提供了很多的API供我们使用与数据库进行CRUD的操作,深度研究,其实SqlSession只是一个接口规范,真正干活的是通过一个Execute执行器生成了自己的MappedStatement对象,进行输入输出映射。
-
Mybatis框架的架构图
-
JDBC存在的问题
- 频繁的创建打开和关闭连接,消耗资源
- sql语句硬编码,不利于维护
- sql参数设置硬编码,不利于维护
- 执行完之后的结果获取和遍历比较复杂,存在硬编码,不利于维护,期望是返回一个封装好的java对象。
Mybatis的入门案例(原始Dao层开发)
第一步:导入相关jar包(Mybatis本身jar包和数据库连接jar包)
第二步:配置核心配置文件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>
<!-- 加载规则:首先加载标签内部属性,再加载外部文件,名称相同时,会替换相同名称的内容 -->
<properties resource="jdbc.properties">
<property name="jdbc.username" value="root11"></property>
</properties>
<!--别名配置-->
<typeAliases>
<!--单个别名设置-->
<typeAlias alias="user" type="com.pojo.User" />
<!--自动的别名设置:扫描包下面的所有的类,设置的别名为类名,不区分大小写-->
<package name="com" />
</typeAliases>
<environments default="development">
<environment id="development">
<!--事物管理:使用JDBC的提交和回滚设置,依赖于从数据源的到的连接来管理事物-->
<transactionManager type="JDBC" />
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClass}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!--导入sql映射配置文件-->
<mappers>
<!-- 引入sql映射文件userMapper.xml文件,
userMapper.xml位于com这个包下,所以resource写成com/userMapper.xml-->
<mapper resource="com/dao/UserDao.xml"/>
<!--class扫描器的要求:
1.sql映射文件必须和接口在同一个目录下
2.映射文件的名字要和接口名一样
-->
<mapper class="com.mappers.UserMappers"></mapper>
<!-- 第三种方式,包扫描器要求(推荐使用此方式):
1、映射文件与接口同一目录下
2、映射文件名必需与接口文件名称一致
-->
<package name="com.mappers"/>
</mappers>
</configuration>
第三步:配置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">
<!--使用的dtd约束,标签必须严格按照顺序-->
<!--
namespace:命名空间,相当于包名,用来区分sql ID
#{ } : 相当于sql语句中的占位符 ?
-->
<mapper namespace="user">
<!--
parameterType:传入参数的类型
resultType:执行完sql之后返回的查询结果
#{ }中的参数随便写
mybatis只能传一个参数,那当传多个参数的时候怎么办呢?,将不在一个对象的两个参数放在一个对象中,使用#{0},#{1}
索引的方式,或者对象中有该属性的get方法,但是前提属性名和 #{名字} 要一致才可以。
${ }:标识符,用于字符串的拼装,当parameterType是基本类型的时候,${value},只能写value,当时其他的引用类型,可以随便写,前提是传递单个参数。
当传递多个参数时候,就不能随便写了,下篇博客会具体讲解。
例如:select * from user where username like '%${value}%'
-->
<select id="findUserById" parameterType="int" resultType="com.pojo.User">
select * from user where id = #{ida}
</select>
<!--resultType:返回的是集合的时候,返回的类型写集合中保存元素的类型-->
<select id="findUserByAll" resultType="com.pojo.User">
select * from user
</select>
<!--使用User类中的get方法获取参数的值-->
<!--
userGnerateKeys:使用生成的key,默认false,标识插入使用自增id,将id绑定在keyProperty属性上,配套使用
只是简化了写selectKey属性的步骤,底层还是调用了 LAST_INSERT_ID()函数
-->
<insert id="insertUser" parameterType="com.pojo.User" useGeneratedKeys="true" keyProperty="id">
<!-- <selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>-->
INSERT INTO `user` (
`username`,
`birthday`,
`sex`,
`address`
)
VALUES
(
#{username},
#{birthday},
#{sex},
#{address}
)
</insert>
<!---->
<delete id="deleteUser" parameterType="int">
DELETE FROM `user` WHERE `id` = #{id}
</delete>
<update id="updateUser" parameterType="com.pojo.User" >
<!--<selectKey keyProperty="uuid" resultType="string" order="AFTER">-->
<!--SELECT UUID()-->
<!--</selectKey>-->
update user set `username` = #{username} where id = #{id}
</update>
</mapper>
第四步:配置日志文件log4j.properties和jdbc.properties属性文件
log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456
第五步:编写测试类
抽取工具类SqlSessionFactoryUtils.java
package com.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class SqlSessionFactoryUtils {
//相当于连接池,一个工程只能有一个,为什么不是SqlSession对象呢?因为官网说了,SqlSession对象非线程安全的,
//必须保证一个线程有一份SqlSession
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用mybatis提供的Resource加载配置文件
InputStream inputStream = null;
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//根据配置文件生成SqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
实现类,dao层
public class UserDaoImpl implements UserDao {
@Override
public User findUserById(int id) throws IOException {
// InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//自己抽取工具类,实现一个工程只有一个工厂
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("findUserById",1);
sqlSession.close();
return user;
}
@Override
public List<User> findUserByAll() throws IOException {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("findUserByAll");
return list;
}
@Override
public void insertUser() throws IOException {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUsername("侯征明3");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("ads");
sqlSession.insert("insertUser", user);
System.out.println(user);
sqlSession.commit();
sqlSession.close();
}
@Override
public void deleteUser(int id) throws IOException {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("deleteUser",id);
sqlSession.commit();
sqlSession.close();
}
@Override
public void updateUser(int id) throws IOException {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setUsername("王然1");
user.setId(id);
sqlSession.update("updateUser", user);
System.out.println(user);
sqlSession.commit();
sqlSession.close();
}
}
Mybatis框架Dao层开发使用接口动态代理
就是之前dao层自己写接口和实现类,现在是只写接口,实现类动态代理得到。
- dao层动态代理的sql映射文件的写法规则
- namespace必须是接口的全路径名称
- 接口的方法名必须和配置文件中的 SQL ID相同
- 接口的方法的参数类型必须和配置文件中的parameterType属性值相同
- 接口的方法返回值必须和配置文件中的resultType属性值相同
Mybatis配置文件详解
配置文件使用的是dtd约束,所以标签的写法一定按顺序写,否则报错。
- properties标签
<!-- 引入外部的jdbc.properties属性文件,相对路径是src目录下
加载规则:首先加载标签内部属性,再加载外部文件,名称相同时,会替换相同名称的内容
-->
<properties resource="jdbc.properties">
<property name="jdbc.username" value="root11"></property>
</properties>
- typeAliases标签
设置完别名之后,以后在sql映射文件中用到的话直接写别名就可以,比如parameterType、resultType等。
<!--别名配置-->
<typeAliases>
<!--单个别名设置-->
<typeAlias alias="user" type="com.pojo.User" />
<!--自动的别名设置:扫描包下面的所有的类,设置的别名为类名,不区分大小写-->
<package name="com" />
</typeAliases>
注解别名设置
@Alias(“user”)
public class student{}
注意:注解别名会覆盖配置文件中的typeAliases配置。
除了自己定义别名外,Mybatis框架对java的基本类型及其他的特殊类型也做了别名映射关系。
- mappers标签
<!--导入sql映射配置文件-->
<mappers>
<!-- 引入sql映射文件userMapper.xml文件,
相对路径是src目录
userMapper.xml位于com这个包下,所以resource写成com/userMapper.xml-->
<mapper resource="com/dao/UserDao.xml"/>
<!--class扫描器的要求:
1.sql映射文件必须和接口在同一个目录下
2.映射文件的名字要和接口名一样
-->
<mapper class="com.mappers.UserMappers"></mapper>
<!-- 第三种方式,包扫描器要求(推荐使用此方式):
1、映射文件与接口同一目录下
2、映射文件名必需与接口文件名称一致
-->
<package name="com.mappers"/>
</mappers>