MyBatis框架教程「实践与工具类封装」

2年前 (2022) 程序员胖胖胖虎阿
248 0 0

MyBatis框架教程「实践与工具类封装」


Web项目聚集地

图文教程,技术交流

MyBatis框架教程「实践与工具类封装」

实践与工具类封装

上一篇文章我们学习了MyBatis框架的环境搭建以及对sqlsessionfactory有个大致的了解,这篇文章就要运用搭建好的环境进行增删改查并且指出一些细节。

同样我们会进行mybatis工具类的封装,把共同的生成sqlSession的代码进行提取封装成工具类,需要sqlSession直接去工具类拿就可以了。文章中我们还可以学习到一些关于日志处理的知识,初步对单元测试的使用。

MyBatis框架教程「实践与工具类封装」

我们的案例使用的简单的Java项目不是基于动态web项目,因为我们现在处于学习阶段,关于SSM框架的整合会在以后的文章中进行详细的讲解。

1.案例截图

MyBatis框架教程「实践与工具类封装」

2. User.java

public class User {
private Integer user_id;
private String user_name;
private String account;
private String password;
private Integer status;  
}

注意:由于篇幅限制,我们对User属性的getter,setter和tostring方法进行省略

3. mybatis-config.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTDConfig 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">

 <configuration>
   <!-- 配置环境 -->
  <environments default="jujidi">
   <environment id="jujidi">
    <transactionManager type="JDBC"></transactionManager>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/dbname"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
 </environments>
 <!-- 加载映射文件 -->
 <mappers>
   <mapper resource="com/jujidi/test/TestMapper.xml" />
 </mappers>
</configuration>

这是Mybatis框架的核心配置文件,其中配置了相关环境和加载映射文件,环境中确定数据源,在数据源中配置你需要链接数据库的相关信息,比如用户名、密码。映射文件就是你编写SQL的xml,通过此核心配置文件进行加载关联。

注意这里的关键点:

  • 默认的环境 ID(default="development")

  • 每个 environment 元素定义的环境 ID

  • 事务管理器的配置(type="JDBC")

  • 数据源的配置(type="POOLED")

可以对环境随意命名,但一定要保证默认的环境 ID 要只匹配其中一个环境 ID


4. TestMapper.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jujidi.model.User">
<!-- 通过id返回数据 -->
<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
   select * from user where user_id=#{user_id}
</select>
<select id="userList" resultType="map">
  select * from user
</select>
<select id="count" resultType="integer">
   select count(*) from user
</select>
<insert useGeneratedKeys="true" keyProperty="user_id" id="add" parameterType="com.jujidi.test.User" >
   insert into user(user_name,account,password) values (#{user_name},#{account},#{password})
</insert>
</mapper>

Mapper是映射文件,对应多个标签(可以理解为SQL),每一个标签有唯一的id用来定位。

上方的代码是此文章案例使用的配置,下面我们扩展MyBatis进行简单增删改查的mapper文件写法:

5.  映射文件写法扩展

插入:

<mapper namespace="com.jujidi.model.User">
   <insert id="insertPerson" parameterType="com.jujidi.model.User">
     INSERT INTO user(user_name,password) VALUES(#{name},#{password})
   </insert>
 </mapper>

 <mapper namespace="需要实现接口的全限定类名">
  <insert id="需要实现的接口里的方法名" parameterType="方法参数类型,如果是对象要写全限定类名">
   INSERT sql命令(命令里通过#{}获取对象属性)
 </insert>
 <mapper>

查询:

<!-- 通过id返回数据 -->
<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
 select * from user where user_id=#{user_id}
</select>

<select id="方法名"  parameterType="方法参数类型"  resultType="方法返回值类型,全类名">
 SELECT 表里字段名 AS 结果字段名 FROM 表名 WHERE 条件
 <!--注意:结果字段名与属性名保持一致,区分大小写-->
</select>

修改:

<update id="updateUserById" parameterType="com.jujidi.test.User">  
  update user  
        set name=#{name},status=#{status}  
     where user_id=#{user_id}  
</update>

删除:

<delete id="deleteUserById"parameterType="int">  
  delete from user  
   where user_id=#{id}  
</delete>

关于传递参数:

<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
    select * from user where user_id=#{user_id}
</select>

通过上面几行代码描述:在mybatis映射文件的配置中,有select等标签都提到了parameterType属性,parameterType为输入参数,在配置的时候,配置相应的输入参数类型即可。

parameterType有基本数据类型和复杂的数据类型配置:

1.基本数据类型,如输入参数只有一个,其数据类型可以是基本的数据类型

2.复杂数据类型:包含java实体类,map

6. 映射文件配置详解

<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
  select * from user where user_id=#{user_id}
</select>
<select id="userList" resultType="map">
  select * from user
</select>

第一个select标签:此标签id为load,传入integer类型的user_id,去user表中查询此id的用户信息,把结果返回。返回值的类型为User对象。

第二个select标签:此标签id为userList,不需要参数,去user表中查询所有用户信息,进行结果反回。返回值的类型为map。

上方的两条select语句中,有一个属性是:resultType是SQL映射文件中定义返回值类型,返回值有基本类型,对象类型,List类型,Map类型等。

  • 基本类型:resultType=基本类型

  • List类型:resultType=List中元素的类型

  • Map类型 

    • 单条记录:resultType=map

    • 多条记录:resultType =Map中value的类型

代码中第一条select语句的resultType使用的对象类型,resultType直接写的对象User的全类名,而第二条select语句返回类型使用的是map,显然效果都是一样的。

7. 为什么是使用map而不是Map呢?

刚刚配置中的resultType="map",为什么是map,不是Map呢?

如果想写Map,需要写成全限定类名,即:resultType = "java.util.Map" map是java.util.Map的一个简写,还有其他的简写可以参考下方表格:

MyBatis框架教程「实践与工具类封装」

MyBatis框架教程「实践与工具类封装」

我们看下方两个语句的resultType:

<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
  select * from user where user_id=#{user_id}
</select>
<select id="userList" resultType="map">
  select * from user
</select>

对于resultType属性,填写User的全类名和map类型效果都一样,还是有一些区别的。比如:如果使用User的全类名作为resultType的参数的话,我们需要保证实体类的属性名字和数据库字段的名字相同,否则的话是接不到值的。

想要实体类的属性和数据库字段不相同,我们有办法解决,可以通过更改SQL语句(别名)等方式来达到目的。

除了resultType属性外还有一个叫做:resultMap,它们俩的区别在后面的文章进行讲解。

8. MyBatisTest.java

public class MybatisTest {
public static void main(String[] args ) {
 SqlSession sqlSession = null;
 try{
     //加载核心配置文件
     InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
     //创建sqlsession工厂 -->相当于connection
     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
     //获取sqlsession -->相当于执行sql语句对象
     sqlSession = sqlSessionFactory.openSession();
     //执行sql
    User user = sqlSession.selectOne("com.jujidi.model.User.load",1);
     System.out.println(user);
     List<Map<String,Object>> userList = sqlSession.selectList("com.jujidi.model.User.userList");
     System.out.println(userList);
     Integer count =sqlSession.selectOne("com.jujidi.model.User.count");
     System.out.println(count);
     }catch( Exception e){
    // TODO Auto-generated catch block
    e.printStackTrace();
     }finally{
        if(sqlSession!=null){
     sqlSession.close();
    }
  }
}
}

上方是测试类,测试类中我们加载核心配置文件、利用核心配置文件的信息来获取sqlsession工厂,工厂生成sqlsession。然后定位映射文件Mapper中的SQL语句进行执行相应查询方法。

9. 事务的提交

测试类中执行下方的insert方法:

public class MybatisTest {
public static void main(String[] args ) {
 SqlSession sqlSession = null;
 try{
      //加载核心配置文件
     InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
     //创建sqlsession工厂 -->相当于connection
     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
     //获取sqlsession -->相当于执行sql语句对象
     sqlSession = sqlSessionFactory.openSession();
    User user = new User();
    user.setAccount("admin");
    user.setPassword("123");
    user.setUser_name("王久一");
    sqlSession.insert("com.jujidi.model.User.add",user);
    }catch( Exception e){
     // TODO Auto-generated catch block
     e.printStackTrace();
    }finally{
        if(sqlSession!=null){
      sqlSession.close();
     }
  }
 }

}

Mapper.xml中语句为:

<insert useGeneratedKeys="true" keyProperty="user_id" id="add" parameterType="com.jujidi.test.User" >
  insert into user(user_name,account,password) values (#{user_name},#{account},#{password})
</insert>

当我们执行insert方法时候,我们会发现:运行期间没有报错,但是数据库中并没有多出刚刚插入的记录。

这是因为进行了插入事务,事务并没有提交。不像以前学习的JDBC会自动提交事务。当我们利用MyBatis执行插入语句后,好像我们使用Navicat工具修改了表中的数据没有点保存一样。必须手动进行提交事务,我们对代码做出如下修改:

MybatisTest .java

public class MybatisTest {
public static void main(String[] args ) {
  SqlSession sqlSession = null;
  try{
      //加载核心配置文件
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    //创建sqlsession工厂 -->相当于connection
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    //获取sqlsession -->相当于执行sql语句对象
    sqlSession = sqlSessionFactory.openSession();
    User user = new User();
    user.setAccount("admin");
    user.setPassword("123");
    user.setUser_name("王久一");
    sqlSession.insert("com.jujidi.model.User.add",user);
   
sqlSession.commit();
    System.out.println(user.getUser_id());
    }catch( Exception e){
     // TODO Auto-generated catch block
     e.printStackTrace();
    }finally{
       if(sqlSession!=null){
      sqlSession.close();
     }
   }
 }
}

加上了sqlSession.commit()语句,这时候就可以成功的修改表中的数据。还有一个比较神奇的小细节:在我们还没有添加sqlSession.commit()语句时,虽然运行后没办法真正插入一条数据,但是想要插入数据的ID还是会生成的。

10. 获取ID

当我们插入了一条数据,怎么来获得新插入的数据的id?

再回到这条mapper语句:

<insert useGeneratedKeys="true" keyProperty="user_id"  id="add"  parameterType="com.jujidi.test.User" >
  insert into user(user_name,account,password) values (#{user_name},#{account},#{password})
</insert>

上方的insert标签属性添加了:

useGeneratedKeys="true" keyProperty="user_id"

 这两个属性后,执行下方的代码:

sqlSession.insert("com.jujidi.model.User.add",user);
sqlSession.commit();
System.out.println(user.getUser_id());

提交插入一条记录后,可以通过user.getUser_id()来获取刚插入记录的ID.

11. MyBatis工具类的封装

我们发现当使用Mybatis进行操作时,加载核心配置文件、创建sqlsession工厂等都是重复的代码,于是我们想着自己封装一个Mybatis工具类,此工具类负责返回一个sqlsession和一些关闭会话的操作。

工具类:MybatisUtil.java

public final class MybatisUtil {
private MybatisUtil(){}
private static final String PATH = "mybatis-config.xml";
private static InputStream is = null;
private static SqlSessionFactory sqlSessionFactory = null;
static{
  try{
     //加载核心配置文件
      is = Resources.getResourceAsStream(PATH);
      //创建sqlsession工厂 -->相当于connection
      sqlSessionFactory = newSqlSessionFactoryBuilder().build(is);
      }catch(Exception e){
     e.printStackTrace();
     throw new RuntimeException("加载映射文件失败可能是你的映射文件写错了原因:"+e.getMessage());
     }
   }
   //获取sqlsession -->相当于执行sql语句对象
   public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession();
   }
   public static void closeSqlSession(SqlSession sqlSession){
    if(sqlSession!=null){
      sqlSession.close();
   }
 }
}

对于上方配置文件的关键字做出一些解释:

11.1 不可继承

final:不可以被继承

final:修饰一个变量path,变成常量不可以修改其值

11.2 不可实例化

private MybatisUtil(){}

工具类类名是:MybatisUtil。构造方法是用public修饰,但是上方使用了private。我们知道构造方法是用来实例化对象的,private来修饰说明本类不能被实例化。

11.3 初始化

static{
  try{
    ...
   }catch(IOException e){
     ...
   }
  }

上方代码:类加载就会加载静态代码块的代码 ,类初始化的时候就加载配置文件获取工厂。

11.4异常处理

catch(IOException e){
 e.printStackTrace();
 throw new RuntimeException("加载映射文件失败可能是你的映射文件写错了原因:"+e.getMessage());
}

对于catch到的异常 "加载映射文件失败,可能是映射文件写错了"要解释一下:

1. mybatis-config 配置了映射文件,映射文件配置出错,加载核心配置文件的时候也会报错 

2. 为什么不提示mybatis-config.xml写错了呢?因为相应的环境参数配置一次就完毕,就是有错误调试成功以后很少会改动xml,而映射文件是常常需要我们编写修改的,所以抛出这样的提示更利于报错的时候准确找到错误。

12.单元测试

我们知道main()方法只能有一个,如果都在main方法里面进行测试代码,就需要注释掉测试完毕的方法,仅仅运行自己当前需要测试的功能方法,这样显得杂乱无章,所以我们学习一下单元测试,不仅对以后的学习有帮助,在工作中也是经常用到。

12.1 新建java工程

添加JUnit相关Jar包

右键项目:Build Path->Configure Builde Path->Add Library->JUnit->Next->Finish

Test01 .java

public class Test01 {
  @Test
 public void test01()
{
   System.out.println("王久一");
 }

 @Test
 public void test02()
{
   System.out.println("小小詹");
 }

 @Test
 public void test03()
{
   System.out.println("老邓头");
 }
}

12.2 测试运行

对于上方代码:我们测试test01()方法,只需要选中test01:

MyBatis框架教程「实践与工具类封装」

右键->Run as->JUnit Test:

控制台便会打印出:王久一   

以此类推,我们分别运行test02和test03方法,也会有相同的效果。

接下来修改代码:

public class Test01 {
 @Before
 public void before()
{
   System.out.println("Web项目聚集地before");
 }

 @After
 public void after()
{
  System.out.println("Web项目聚集地after");
 }

  @Test
 public void test01()
{
   System.out.println("王久一");
 }

 @Test
 public void test02()
{
   System.out.println("小小詹");
 }

 @Test
 public void test03()
{
   System.out.println("老邓头");
 }
}

12.3 再次运行

测试test01()方法,控制台打印为:

MyBatis框架教程「实践与工具类封装」

添加@Before和 @After注解后,产生的效果可想而知。

12.4 一起运行

如果不单个运行,一起运行是什么效果呢? 

MyBatis框架教程「实践与工具类封装」

13.  log4j日志包

最后方便开发调试,我们需要增加日志功能:

导入log4j包

在classpath下添加log4j.properties文件:

# Global loggingconfiguration
log4j.rootLogger=ERROR,stdout
# 注意log4j.logger后面是需要日志处理mapper的namespace名称
log4j.logger.com.jujidi.model.User=TRACE
# 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

通过第四行的配置和映射文件关联,在执行相关联mapper中的SQL就会在控制台打印出日志信息。

重要说明:实际开发中是不会使用Mybatis工具类来进行开发的,而是SSM框架整合后,通过接口代理的方式来实现对数据库的操纵。

为了使初学者对Mybatis框架有一个独立且系统的认识,所以采用这种系统的教学方式,而不是一开始就是整合。我们会在学习过程中逐渐拓展,最终达到实际开发所需要的本领。

如果您觉得此平台教程不错的话,欢迎推荐给自己的朋友!



1. MyBatis框架教程「入门起步」

2.「SSM实战」从零开发内容管理系统

3. 从零开发一个JavaWeb项目要点「建议收藏」

4. Maven学习笔记(二)

MyBatis框架教程「实践与工具类封装」

本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

版权声明:程序员胖胖胖虎阿 发表于 2022年9月18日 下午11:56。
转载请注明:MyBatis框架教程「实践与工具类封装」 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...