Mybatis学习一 CRUD的实现
前言:关于 mybatis 的博文,我没有很详细的去介绍每个类、每个注解或每个配置标签的详细作用。更多情况下是直接通过代码的方式“不求甚解”的来学习如何使用 mybatis,如果想更深入了解 mybatis 的一些类、注解或标签的作用,可以下载文章最后的附件。它是官方文档的中文版,里面很详细介绍了 mybatis 的内容。
Mybatis 是支持普通SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC 代码和参数的手工设置以及对结果集的检索。
MyBatis 可以使用简单的XML或注解用于配置和原始映射,将接口和 Java 的 POJO 映射成数据库中的记录。
在使用 Mybatis 之前我们还需要做一些准备工作。
首先导入 Mybatis 的 jar 包,同时还需要导入 Mysql 驱动包
在 Mysql 数据库中新建库和表
create database test; use test; CREATE TABLE user(id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT); INSERT INTO user(NAME, age) VALUES('Tom', 20); INSERT INTO user(NAME, age) VALUES('Jack', 25);
准备工作完成后,我们就真正来看如何通过 mybatis 实现 CRUD
文件结构如下图
新建一个叫 mybatis-test 的 java 工程,src 下新建一个名为 mybatis-conf.xml 的文件作为 Mybatis 的配置文件
<?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> <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://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="000"/> </dataSource> </environment> </environments> </configuration>
注:
1. <environments> 的 default 属性有两个值,一个是指代开发模式:development;还有一个指代工作模式:work。 <environments> 中的 id 属性要与该属性一致。
2. <transactionManager> 中 type 属性标识了 Mybatis 中的两种事务管理器类型
a. JDBC:这个配置直接简单使用了JDBC的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。
b. MANAGED:这个配置几乎没做什么。他从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期(比如 Spring 或 J2EE 应用服务器的上下文)。默认情况下它会关闭连接。
3. dataSource 元素使用基本的JDBC数据源接口来配置JDBC连接对象的资源。有三种内建的数据源类型
a. UNPOOLED:这个数据源的实现是每次被请求时简单打开和关闭连接。
b. POOLED:这是JDBC连接对象的数据源连接池的实现,用来避免创建新的连接实例时必要的初始连接和认证时间。
c. JNDI:这个数据源的实现是为了使用如 Spring 或应用服务器这类的容器,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。
接下来,新建一个与数据库对应的实体类
package com.bupt.mybatis.beans; public class User { private int id; private String name; private int age;
//生成 getter、setter方法,带参和不带参的构造器,重写toString }
Mybatis 真正的方便之处在于映射语句中。如果你将它们和对等功能的JDBC代码来比较的话,你会发现映射文件节省了大量的代码量。Mybatis的构建就是聚焦于SQL的,使其原理普通的方式。
所以这里我们需要定义操作 user 表的 SQL 映射文件 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">
<!-- namespace 属性值通常写为:映射文件所在包名+映射文件名去掉.xml后缀 --!>
<mapper namespace="com.bupt.mybatis.beanMappers.userMapper">
<!-- parameterType指定查询时传递参数的类型,resultType为查询结果类型,需要写全类名 --!>
<select id="getUser" parameterType="int" resultType="com.bupt.mybatis.beans.User"> select * from user where id=#{id} </select>
<!-- 用#{}方式来作为传参占位符,括号内的元素需与定义在实体类中的属性一致 --!> <insert id="addUser" parameterType="com.bupt.mybatis.beans.User"> insert into user(id, name, age) values(#{id}, #{name}, #{age}) </insert>
<!-- parameterType为测试时传入的参数类型 --!> <delete id="deleteUser" parameterType="int"> delete from user where id=#{id} </delete> <update id="updateUser" parameterType="com.bupt.mybatis.beans.User"> update user set name=#{name}, age=#{age} where id=#{id} </update>
<!-- 当查询多条语句时,返回值为List<T>类型的,但其每条记录还是User类型 --!> <select id="getAll" resultType="com.bupt.mybatis.beans.User"> select * from user </select> </mapper>
编写好SQL映射文件后,我们还需要将此配置信息注册到 mybatis-conf.xml 文件中,注册时使用 <mappers> 和 <mapper> 标签,位置为 <environments>外,<configuration> 内
注意文件位置和编写格式
<mappers> <mapper resource="com/bupt/mybatis/beanMappers/userMapper.xml"/> </mappers>
配置好 SQL 映射文件后,我们就可以编写测试类了
注:每个线程都应该有自己的 SqlSession 实例,SqlSession 的实例不能共享使用,它是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能把 SqlSession 实例放在一类的静态字段甚至是实例字段中。也绝对不能将 SqlSession 实例的引用放在任何类型的管理范围内,比如 Servlet 架构中的 HttpSession。
package com.bupt.mybatis.test; import java.io.InputStream; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.bupt.mybatis.beans.User; public class TestCRUD { //指明需要加载的mybatis配置文件,需要写绝对路径 String resource = "mybatis-conf.xml"; //类加载加载 mybatis 配置文件 InputStream is = TestCRUD.class.getClassLoader().getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); //使用 mybatis 提供的工具类 Resources 加载 mybatis 的配置文件 //Reader reader = Resources.getResourceAsReader(resource); //SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); @Test public void testSelect() { //如果要往数据库中提交事务,需要传递参数true。如果没有设置参数true,则执行完SQL语句后,数据库中不会有对应的记录 SqlSession session = sessionFactory.openSession(true); //statement格式为:SQL映射文件中的namespace+要执行的SQL语句在映射文件中的id值 String statement = "com.bupt.mybatis.beanMappers.userMapper.getUser"; //session操作要放在try-catch模块中,下面的方法没写是偷懒 try { User user = session.selectOne(statement, 2); //除了在openSession()方法中传递true参数之外,还可以使用commit()方法手动提交事务 //session.commit(); } catch (Exception e) { e.printStackTrace(); } finally { //关闭资源 session.close(); } System.out.println(user); } public void testAdd() { SqlSession session = sessionFactory.openSession(true); String statement = "com.bupt.mybatis.beanMappers.userMapper.addUser"; int i = session.insert(statement, new User(3, "Jerry", 40)); session.close(); System.out.println(i); } public void testDelete() { SqlSession session = sessionFactory.openSession(true); String statement = "com.bupt.mybatis.beanMappers.userMapper.deleteUser"; int i = session.delete(statement, 3); session.close(); System.out.println(i); } public void testUpdate() { SqlSession session = sessionFactory.openSession(true); String statement = "com.bupt.mybatis.beanMappers.userMapper.updateUser"; int i = session.update(statement, new User(2, "Kim", 22)); session.close(); System.out.println(i); } public void testSelectAll() { SqlSession session = sessionFactory.openSession(true); String statement = "com.bupt.mybatis.beanMappers.userMapper.getAll"; List<User> users = session.selectList(statement); session.close(); System.out.println(users); } }
除了通过编写SQL映射文件的方式来实现 Mybatis 的CRUD之外,还可以通过注解的方式来实现
首先我们需要定义 SQL 映射的接口
package com.bupt.mybatis.annoMappers; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import com.bupt.mybatis.beans.User; public interface UserMapper { @Select("select * from user where id=#{id}") public User getUserById(int id); @Select("select * from user") public List<User> getAllUser(); @Insert("insert into user(id, name, age) values (#{id}, #{name}, #{age})") public int insertUser(User user); @Delete("delete from user where id=#{id}") public int deleteUserById(int id); @Update("update user set name=#{name}, age=#{age} where id=#{id}") public int updateUser(User user); }
在 mybatis-conf.xml 中注册这个映射的接口,位置与编写的xml形式的映射文件一致,但需要注意两者注册信息书写格式的区别
<mappers>
<mapper class="com.bupt.mybatis.annoMappers.UserMapper"/>
</mappers>
用这种方式实现时,我们就不用编写映射文件 userMapper.xml
编写测试类
注:映射器实例的最佳范围是方法范围。
package com.bupt.mybatis.test; import java.io.InputStream; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.bupt.mybatis.annoMappers.UserMapper1; import com.bupt.mybatis.beans.User; public class TestCRUDByAnno { InputStream is = TestCRUDByAnno.class.getClassLoader().getResourceAsStream("mybatis-conf.xml"); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is); //偷懒写法,要把session操作放入try-catch模块 public void testGetUserById() { SqlSession session=sessionFactory.openSession(true); UserMapper mapper=session.getMapper(UserMapper1.class); User user = mapper.getUserById1(1); session.close(); System.out.println(user); } public void testGetAll() { SqlSession session=sessionFactory.openSession(true); UserMapper mapper=session.getMapper(UserMapper1.class); List<User> users = mapper.getAllUser(); session.close(); System.out.println(users); } public void testInsertUser() { SqlSession session=sessionFactory.openSession(true); UserMapper mapper=session.getMapper(UserMapper1.class); int i = mapper.insertUser1(new User(3, "Jack", 30)); session.close(); System.out.println(i); } @Test public void testDeleteUser() { SqlSession session=sessionFactory.openSession(true); UserMapper mapper=session.getMapper(UserMapper1.class); int i = mapper.deleteUserById1(3); session.close(); System.out.println(i); } public void testUpdate() { SqlSession session=sessionFactory.openSession(true); UserMapper mapper=session.getMapper(UserMapper1.class); int i = mapper.updateUser(new User(2, "Lily", 25)); session.close(); System.out.println(i); } }
在实际中,用的更多的情况其实是 配置映射文件 + 接口的方式来实现 CRUD
这时我们在接口类中只定义方法,而不在其上面添加注解,需注意的是接口中的方法名需与在映射配置文件中定义的 id 属性一致
package com.bupt.mybatis.annoMappers; import java.util.List; import com.bupt.mybatis.beans.User; public interface UserMapper1 { public User getUserById(int id); public List<User> getAllUser(); public int insertUser(User user); public int deleteUserById(int id); public int updateUser(User user); }
在编写映射配置文件时需注意,此时的 namespace 属性值需要与接口类的全类名一致,如此才能将映射文件与接口类关联起来
<?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.bupt.mybatis.annoMappers.UserMapper1"> <select id="getUserById" parameterType="int" resultType="User"> select * from user where id=#{id} </select> <select id="getAllUser" resultType="User"> select * from user </select> <insert id="insertUser" parameterType="User"> insert into user(id, name, age) values(#{id}, #{name}, #{age}) </insert> <delete id="deleteUserById" parameterType="int"> delete from user where id=#{id} </delete> <update id="updateUser" parameterType="User"> update user set name=#{name}, age=#{age} where id=#{id} </update> </mapper>
测试类与之前注解修饰接口时使用的测试类一致。
在上面的程序中,还有几个可以优化的地方
1. 连接数据库的配置可以单独放置到一个properties文件中
##src下新建db.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql:///test username=root password=000
相应的 mybatis-conf.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="db.properties"/>
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> </configuration>
2. 在编写SQL映射文件指定 parameterType 或 resultType 时,会大量使用到实体类的全名,非常麻烦。
我们可以在 mybatis-conf.xml 中声明一个类别名来代替使用,声明时使用 <typeAliases> 标签,位置<environments>外,<configuration>内
<typeAliases> <!-- 当在SQL映射文件中出现com.bupt.mybatis.beans.User时,就可以用_User来代替了 --> <typeAlias type="com.bupt.mybatis.beans.User" alias="_User"/> </typeAliases>
但当存在大量的实体类时,我们就需要编写大量的声明标签,同样很麻烦。
在实际编写代码时,我们通常把实体类放置到同一个包下,这时我们就可以使用 <typeAliases> 中另外一个 <package name=""/> 标签,来简化存在多个实体类情况下的声明
当我们在 <package> 标签中的 name 属性填写了某个实体类包名时,编写SQL映射文件时不在需要写实体类的全类名,也不需要手动指定别名,直接默认使用类名代替即可,如此例中。
<typeAliases>
<package name="com.bupt.mybatis.beans"/>
</typeAliases>
当我们作了如上说明,当在SQL映射文件中出现 com.bupt.mybatis.beans.User (全类名)时,就可以用User(类名)来代替了。
Mybatis 中文官方文档
https://files.cnblogs.com/files/2015110615L/MyBatis-3-User-Guide-Simplified-Chinese.pdf
posted on 2016-04-02 10:10 Traveling_Light_CC 阅读(185) 评论(0) 编辑 收藏 举报