Mybatis及其使用
一、MyBatis的基础用法
mybatis-3.4.4.jar
https://github.com/mybatis/mybatis-3/releases
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old JavaObjects,普通的 Java对象)映射成数据库中的记录。1.1、从 XML 中构建 SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。但是也可以使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者 file:// 的 URL 形式的文件路径来配置。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,可使从 classpath 或其他位置加载资源文件更加容易。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1.2、从 SqlSessionFactory 中获取 SqlSession
既然有了 SqlSessionFactory ,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。SqlSession session = sqlSessionFactory.openSession();
try {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
session.close();
}
1.3、示例
1、全局配置文件<?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>
<typeAlias type="com.data.UserDao" alias="UserDao" />
</typeAliases>
<!-- 配置环境变量 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://10.108.171.181:3306/mybatis?characterEncoding=GBK" />
<property name="username" value="root" />
<property name="password" value="www1234" />
</dataSource>
</environment>
</environments>
<!-- 配置mappers -->
<mappers>
<mapper resource="conf/userdao.xml" />
</mappers>
</configuration>
2、Mapper文件
<?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="com.data.UserDao">
<select id="getUser" parameterType="int" resultType="UserDao">
select * from users where age = #{age}
</select>
<insert id="insert" flushCache="true" parameterType="UserDao">
insert into users (id, name, age) values (
#{id}, #{name}, #{age}
)
</insert>
<!-- 对应userDao中的updateUser方法 -->
<update id="update" parameterType="UserDao">
update users set name = #{name}, age = #{age} where id = #{id};
</update>
<!-- 对应userDao中的deleteUser 方法 -->
<delete id="delete" parameterType="int">
delete from users where id = #{id};
</delete>
</mapper>
3、应用实现
public class Main {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("user.dir"));
String resource = "conf/mybatis-config.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(reader);
SqlSession session = sqlSessionFactory.openSession();
// String statement0 = "com.data.UserDao.insert";
// UserDao user0 = new UserDao(5,"www9527",30);
// session.insert(statement0, user0);
// session.commit();
// String statement1 = "com.data.UserDao.update";
// UserDao user1 = new UserDao(5,"www2759",30);
// session.update(statement1, user1);
// session.commit();
String statement1 = "com.data.UserDao.delete";
session.update(statement1, 5);
session.commit();
String statement3= "com.data.UserDao.getUser";
//UserDao user = session.selectOne(statement);
List<UserDao> users = new ArrayList<UserDao>();
users = session.selectList(statement3,30);
System.out.println(users);
}
}
二、原始dao和代理Mapper
2.1、原始dao
2.1.1、编程步骤
1、 根据需求创建po类
2、 编写全局配置文件
3、 根据需求编写映射文件
4、 加载映射文件
5、 编写dao接口
6、 编写dao实现类
7、 编写测试代码
2.1.2、原始Dao实现
1、编写dao接口
public interface UserDao {
// 1、 根据用户ID查询用户信息
public User findUserById(int id) throws Exception;
// 2、 根据用户名称模糊查询用户列表
public List<User> findUsersByName(String name) throws Exception;
// 3、 添加用户
public void insertUser(User user) throws Exception;
}
2、dao接口实现
public class UserDaoImpl implements UserDao {
// 依赖注入
private SqlSessionFactory sqlSessionFactory;
//使用构造方法来初始化SqlSessionFactory
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
// 通过工厂在方法内部获取sqlsession,这样可以避免线程安全问题
SqlSession sqlSession = sqlSessionFactory.openSession();
// 调用SqlSession的增删改查方法
// 第一个参数:表示statement的唯一标示
User user = sqlSession.selectOne("test.findUserById", id);
System.out.println(user);
// 关闭资源
sqlSession.close();
return user;
}
@Override
public List<User> findUsersByName(String name) {
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 调用SqlSession的增删改查方法
// 第一个参数:表示statement的唯一标示
List<User> list = sqlSession.selectOne("test.findUsersByName", name);
System.out.println(list);
// 关闭资源
sqlSession.close();
return list;
}
@Override
public void insertUser(User user) {
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 调用SqlSession的增删改查方法
// 第一个参数:表示statement的唯一标示
sqlSession.insert("test.insertUser", user);
System.out.println(user.getId());
// 提交事务
sqlSession.commit();
// 关闭资源
sqlSession.close();
}
}
3、Test
public class UserDaoTest {
//声明全局的SqlSessionFactory
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
// 1、读取配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件创建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() {
//构造UserDao对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//调用UserDao对象的方法
User user = userDao.findUserById(1);
System.out.println(user);
}
@Test
public void testFindUsersByName() {
//构造UserDao对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//调用UserDao对象的方法
List<User> list = userDao.findUsersByName("小明");
System.out.println(list);
}
@Test
public void testInsertUser() {
//构造UserDao对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//构造User对象
User user = new User();
user.setUsername("东哥3");
user.setAddress("清河宝盛西里3");
//调用UserDao对象的方法
userDao.insertUser(user);
System.out.println(user.getId());
}
}
4、问题总结
原始dao开发存在一些问题:
存在一定量的模板代码。比如:通过SqlSessionFactory创建SqlSession;调用SqlSession的方法操作数据库;关闭Sqlsession。
存在一些硬编码。调用SqlSession的方法操作数据库时,需要指定statement的id,这里存在了硬编码。
2.2、Mapper代理开发方式
2.2.1、开发规范
1、 mapper接口的全限定名要和mapper映射文件的namespace的值相同。
2、 mapper接口的方法名称要和mapper映射文件中的statement的id相同;
3、 mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
4、 mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;
2.2.2、编程步骤
1、 根据需求创建po类
2、 编写全局配置文件
3、 根据需求编写映射文件
4、 加载映射文件
5、 编写mapper接口
6、 编写测试代码
2.2.3、实现
1、Mapper映射文件
<?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:此时用mapper代理方式,它的值必须等于对应mapper接口的全限定名 -->
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<!-- 根据用户ID,查询用户信息 -->
<!--
[id]:statement的id,要求在命名空间内唯一
[parameterType]:入参的java类型,可是是简单类型、POJO、HashMap
[resultType]:查询出的单条结果集对应的java类型
[#{}]: 表示一个占位符?
[#{id}]:表示该占位符待接收参数的名称为id。注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义
-->
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
SELECT * FROM USER WHERE id = #{id}
</select>
<!-- 根据用户名称模糊查询用户信息列表 -->
<!--
[${}]:表示拼接SQL字符串,即不加解释的原样输出
[${value}]:表示要拼接的是简单类型参数。
注意:
1、如果参数为简单类型时,${}里面的参数名称必须为value
2、${}会引起SQL注入,一般情况下不推荐使用。但是有些场景必须使用${},比如order by ${colname}
-->
<select id="findUsersByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
<!-- 添加用户之自增主键返回(selectKey方式) -->
<!--
[selectKey标签]:通过select查询来生成主键
[keyProperty]:指定存放生成主键的属性
[resultType]:生成主键所对应的Java类型
[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句,此时选用AFTER
[last_insert_id]:MySQL的函数,要配合insert语句一起使用
-->
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO USER(username,sex,birthday,address) VALUES (#{username},#{sex},#{birthday},#{address})
</insert>
</mapper>
2、加载映射文件
在SqlMapConfig.xml文件中:
<!-- 加载mapper -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
3、编写UserDao接口一样
public interface UserMapper {
//根据用户ID来查询用户信息
public User findUserById(int id);
//根据用户名称来模糊查询用户信息列表
public List<User> findUsersByName(String username);
//添加用户
public void insertUser(User user);
}
4、测试类
public class UserMapperTest {
// 声明全局的SqlSessionFactory
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
// 1、读取配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件创建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() {
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession,获取mapper接口的动态代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用mapper对象的方法
User user = userMapper.findUserById(1);
System.out.println(user);
// 关闭SqlSession
sqlSession.close();
}
@Test
public void testFindUsersByName() {
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession,获取mapper接口的动态代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用mapper对象的方法
List<User> list = userMapper.findUsersByName("小明");
System.out.println(list);
// 关闭SqlSession
sqlSession.close();
}
@Test
public void testInsertUser() {
// 创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession,获取mapper接口的动态代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//构造User对象
User user = new User();
user.setUsername("东哥4");
user.setAddress("清河宝盛西里4");
// 调用mapper对象的方法
userMapper.insertUser(user);
System.out.println(user.getId());
//执行SqlSession的commit操作
sqlSession.commit();
// 关闭SqlSession
sqlSession.close();
}
}