mybatis入门案例

mybatis入门案例

  1. 确定需求

    根据用户id查询一个用户信息
    根据用户名称模糊查询用户信息列表
    添加用户
    更新用户
    删除用户
    
  2. 需求分析

    a)根据用户id查询一个用户信息:SELECT * FROM USER WHERE id = 1
    b)根据用户名称模糊查询用户信息列表:SELECT * FROM USER WHERE username LIKE '%张%'
    

    3.实现需求

根据用户id查询用户信息的实现流程:

第一步:
a)创建mybatis的全局配置文件:SqlMapConfig.xml,配置数据源、事务等运行环境,加载Mapper.xml映射文件

使用mybatis-3-config.dtd约束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>
    <!-- 
        和spring整合后 environments配置将废除,只在单独mybatis时使用 
        运行环境,当不指定运行环境时,默认执行default后跟的这个运行环境
    -->
    <environments default="mysql">
        <environment id="mysql">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                    value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="123" />
            </dataSource>
        </environment>
    </environments>
</configuration>

b)创建Mapped.xml
这里写图片描述

早期ibatis的映射文件以表名命名,
后期mybatis映射文件命名方式为:表名Mapper.xml;
所以这个命名方式是不固定的;
这里使用的是早期的命名方式
使用mybatis-3-mapper.dtd约束

- 这里可能会出现代码不联想的问题:解决方案

![](http://img.blog.csdn.net/20180104134052461?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYnN3NDUxOTI2Mzky/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
第二步:点击window,preferences,XML catalog
这里写图片描述
这里写图片描述
这里写图片描述
$$第三步:重新打开即可

c)继续配置Mapped.xml

<!-- 
    一个mapper映射文件,里面是以sql语句为单位进行配置,最终将sql语句封装到MappedStatement对象中
    namespace:命名空间的作用是更好的对sql语句进行隔离,方便管理sql
    注意:mybatis的mapper代理开发方式时namespace还有特殊的作用
 -->
<mapper namespace = "test">
    <!-- 
        根据用户id查询用户信息 
        select:主要用于查询,配置sql语句、输入参数的类型,输出结果的类型
            最终该select标签中所配置的内容会封装到MapperedStatement对象中,可以讲该select称之为statement
        id:是唯一标识namespace下的sql语句,也是statement的id

        parameterType:指定输入参数的类型(简单类型\POJO类型)
        #{}:表示一个占位符
        #{value}:value表示接收一个输入参数的值,如果要接收的输入参数是简单类型,#{}里面可以写value或其他名称
        resultType:将sql查询的结果集映射成java对象
            *号会查询回很多个列的信息,所以需要将结果集封装到一个POJO类中,这个POJO中的属性名称必须与数据表的列名相等
            指定单条记录所映射的java对象
    -->
    <select id="findUserById" parameterType="int" resultType="">
        SELECT * FROM USER WHERE id = #{id}
    </select>

    <!-- 添加用户 -->
    <insert id="">
        <!-- 编写sql语句 -->
    </insert>

    <!-- 删除用户 -->
    <delete id="">
        <!-- 编写sql语句 -->
    </delete>

    <!-- 修改用户 -->
    <update id="">
        <!-- 编写sql语句 -->
    </update>
</mapper>

d)创建对应的POJO类

package com.bsw.domain;

import java.util.Date;

/**
 * User的POJO类
 */
public class User {
    private int id;         // id
    private String username;    // 名称
    private String sex;         // 性别
    private Date birthday;      // 生日
    private String address;     // 地址

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

e)复制User这个POJO的全类名,复制到User.xml中的下图位置
这里写图片描述
这里写图片描述

第二步:
将Mapped.xml(User.xml)加载到全局配置文件(SqlMapConfig.xml)中
这里写图片描述
第三步:
编写以下代码,进行实现功能

package com.bsw.mybatis;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.bsw.domain.User;

/**
 * 
 * mybatis的入门程序
 * @author huihui
 *
 */
public class MybatisDemo {
    // 根据用户id查询用户信息
    @Test
    public void findUserById() throws Exception {
        // mybatis的全局配置文件
        String resource = "SqlMapConfig.xml";

        // 根据mybatis的全局配置文件构造一个输入流
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 创建会话工厂SqlSessionFatory_需要给一个input流,这个流就是配置文件SqlMapConfig.xml
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(inputStream);

        // 创建会话SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 通过会话SqlSession使用sql语句查询
        // 源码中的方法<T> T selectOne(String statement, Object parameter);
        // 第一个参数:statement的id,前边要加namespace(意思就是,namespace的值.statement的id即test.findUserById)
        // 第二个参数:输入的参数对象值
        User user = sqlSession.selectOne("test.findUserById", 1);
        System.out.println(user);

        // 关闭session
        sqlSession.close();
    }
}

第四步:
运行之后报错:
问题1:

org.apache.ibatis.exceptions.PersistenceException: 
### Error building SqlSession.
### The error may exist in sqlmap/User.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for test.
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
    at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)
    at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)
    at com.bsw.mybatis.MybatisDemo.findUserById(MybatisDemo.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for test.
    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:121)
    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:99)
    at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:78)
    ... 25 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for test.
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:120)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:92)
    at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:373)
    at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:119)
    ... 27 more
Caused by: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for test.
    at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:872)
    at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:844)
    at org.apache.ibatis.session.Configuration.addMappedStatement(Configuration.java:668)
    at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:302)
    at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:109)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:135)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:128)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:118)
    ... 30 more

解决:

这个问题是说在Mapped.xml配置文件中存在重复的id或者有id为空,即id=""

结果:
最终结果

根据用户id查询用户信息的实现流程:

第一步:
与上述第一步无恙,只需要在Mapper.xml(User.xml)文件中配置

<!-- 根据用户名称模糊查询用户信息列表 -->
<select id="findUserByUsername" parameterType="java.lang.String" resultType="com.bsw.domain.User">
    <!-- 这里的查询返回属性名(数据表中的列名),必须与POJO中的属性名称一致 -->
    SELECT id,username,birthday,sex,address FROM USER WHERE username LIKE #{username}
    <!--
        第二种:
        ${}:表示一个sql拼接符号,相当于字符串的拼接
        相当于:SELECT * FROM USER WHERE username LIKE '%' + ${value} + '%'
        ${}如果接收的输入参数是简单类型,${}中只能写value
        这么写,在测试类中就可以写以下形式
        List<User> users = sqlSession.selectOne("test.findUserByUsername", "张");
        但是这种sql的拼接,无法防止sql注入问题,所以实际开发中建议使用#{}
    -->
    <!--
        SELECT * FROM USER WHERE username LIKE '%${username}%'
    -->
</select>

第二步:
编写测试代码

// 根据用户名模糊查询用户
    @Test
    public void findUserByUsername() throws IOException {
    // mybatis的全局配置文件
    String resource = "SqlMapConfig.xml";

    // 根据mybatis的全局配置文件构造一个输入流
    InputStream inputStream = Resources.getResourceAsStream(resource);

    // 创建会话工厂SqlSessionFatory_需要给一个input流,这个流就是配置文件SqlMapConfig.xml
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(inputStream);

    // 创建会话SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 通过会话SqlSession使用sql语句查询
    // 源码中的方法<T> T selectOne(String statement, Object parameter);
    // 第一个参数:statement的id,前边要加namespace
    // 第二个参数:输入的参数对象值
    // 注意:这里的方法需要更改,因为可能会查到多条数据,所以不能用selectOne而要根据具体情况进行更改,此处用selectList
    List<User> users = sqlSession.selectList("test.findUserByUsername", "%张%");
    System.out.println(users);

    // 关闭session
    sqlSession.close();
}

运行成功
模糊查询结果图

添加用户

第一步:
与上述无恙,只需要修改Mapper.xml(User.xml)

<!-- 
    添加用户 
    需要输入参数是多个值,如果传入简单类型就无法满足要求,
    输入参数可以定义为POJO(com.bsw.domain.User包含多个属性)
    #{}如何获取对象的值?
    #{}是通过OGNL读取对象的值,OGNL表达式:属性.属性.属性....直到将需要的值取出
    -->
<insert id="addUser" parameterType="com.bsw.domain.User">
    <!-- 编写sql语句 -->
    INSERT INTO USER(username, birthday, sex, address) VALUES(#{username}, #{birthday}, #{sex}, #{address})
</insert>

第二步:
编写测试代码:

// 添加用户
@Test
public void addUser() throws IOException {
    // mybatis的全局配置文件
    String resource = "SqlMapConfig.xml";

    // 根据mybatis的全局配置文件构造一个输入流
    InputStream inputStream = Resources.getResourceAsStream(resource);

    // 创建会话工厂SqlSessionFatory_需要给一个input流,这个流就是配置文件SqlMapConfig.xml
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(inputStream);

    // 创建会话SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 通过会话SqlSession使用sql语句查询
    // 源码中的方法<T> T selectOne(String statement, Object parameter);
    // 第一个参数:statement的id,前边要加namespace
    // 第二个参数:输入的参数对象值--此处创建一个User并赋值
    User user = new User();
    user.setUsername("张三丰");
    user.setBirthday(new Date());
    user.setAddress("北京");

    // 添加用户
    int flag = sqlSession.insert("test.addUser", user);
    // 经测试,添加成功返回值为1
    System.out.println(flag);

    // 提交
    sqlSession.commit();
    // 关闭session
    sqlSession.close();
}

运行结果:
这里写图片描述

添加用户主键返回

  • 需求分析
    当新添加数据之后,需要取出新纪录的主键,如果主键是由程序代码生成的,那么获取比较方便;如果主键是数据库自动生成的,需要通过程序代码来获取新纪录的主键。
    mybatis要实现执行insert后将主键通过输入参数对象返回。
  • 主键返回的两种方式
    1.数据库自增主键的返回
    只需要在上述添加案例的Mapper.xml文件中修改如下代码:
<!-- 
    添加用户 
    需要输入参数是多个值,如果传入简单类型就无法满足要求,
    输入参数可以定义为POJO(com.bsw.domain.User包含多个属性)
    #{}如何获取对象的值?
    #{}是通过OGNL读取对象的值,OGNL表达式:属性.属性.属性....直到将需要的值取出
-->
<insert id="addUser" parameterType="com.bsw.domain.User">
    <!-- 
        获取主键
        selectKey:获取逐渐
        keyProperty:将主键值设置到输入参数的哪个属性中,此案例设置到User的id属性中
        order:selectKey中的sql语句在insert语句执行的前或后,BEFORE或AFTER
        resultTyep:select LAST_INSERT_ID()查询出的值得类型
     -->
     <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        select LAST_INSERT_ID()
     </selectKey>
    <!-- 编写sql语句:因为主键id自增,所以不需要手动设置 -->
    INSERT INTO USER(username, birthday, sex, address) VALUES(#{username}, #{birthday}, #{sex}, #{address})
</insert>

在测试类中添加一条打印主键代码:

System.out.println("主键为:" + user.getId());

即可实现需求
获取数据库自动生成的主键
2.uuid()

    除了自增主键的生成之外,mysql数据库中会自动生成一个唯一的uuid的序列号
    优点:因为是唯一的,所以有利于数据库表的迁移
    缺点:因为位数过长,所以对uuid数据做索引,性能没有对数字型索引的性能高
    结论:推荐使用自增

这里写图片描述
主键返回流程:
需要修改Mapper.xml(User.xml)文件中的insert标签,修改结果如下

<!-- 
    uuid返回主键
-->
<insert id="addUser" parameterType="com.bsw.domain.User">
    <!-- 
        获取主键
        selectKey:获取逐渐
        keyProperty:将主键值设置到输入参数的哪个属性中,此案例设置到User的id属性中
        order:selectKey中的sql语句在insert语句执行的前或后,BEFORE或AFTER
        resultTyep:select LAST_INSERT_ID()查询出的值得类型
     -->
     <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
        select uuid()
     </selectKey>
    <!-- 编写sql语句 -->
    INSERT INTO USER(id, username, birthday, sex, address) VALUES(#{id}, #{username}, #{birthday}, #{sex}, #{address})
</insert>

图中标红需特别注意
uuid返回主键
注意:
此案例用的数据库表中主键为int,如果想要实现uuid返回主键,需要将下图中的int改为varchar
主键类型

删除用户

第一步:
在Mapper.xml(User.xml)中配置如下代码

<!-- 删除用户 -->
<delete id="deleteUser" parameterType="com.bsw.domain.User">
    <!-- 编写sql语句 -->
    DELETE FROM USER WHERE id = #{id}
</delete>

第二步:
在测试类中编写一下代码:

// 删除用户
@Test
public void deleteUser() throws IOException {
    // mybatis的全局配置文件
    String resource = "SqlMapConfig.xml";

    // 根据mybatis的全局配置文件构造一个输入流
    InputStream inputStream = Resources.getResourceAsStream(resource);

    // 创建会话工厂SqlSessionFatory_需要给一个input流,这个流就是配置文件SqlMapConfig.xml
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(inputStream);

    // 创建会话SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 通过会话SqlSession使用sql语句查询
    // 源码中的方法<T> T selectOne(String statement, Object parameter);
    // 第一个参数:statement的id,前边要加namespace

    int flag = sqlSession.delete("test.deleteUser", 31);
    // 删除成功的返回值为1
    System.out.println(flag);

    // 提交
    sqlSession.commit();
    // 关闭session
    sqlSession.close();
}

运行实现
删除用户结果

修改用户

第一步:
在Mapper.xml(User.xml)中的mapper标签下配置如下代码:

<!--修改用户-->
<update id="updateUser" parameterType="com.bsw.domain.User">
    <!-- 编写sql语句 -->
    UPDATE USER SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
</update>

第二步:
在测试类中编写如下代码:

// 修改用户
@Test
public void updateUser() throws IOException {
    // mybatis的全局配置文件
    String resource = "SqlMapConfig.xml";

    // 根据mybatis的全局配置文件构造一个输入流
    InputStream inputStream = Resources.getResourceAsStream(resource);

    // 创建会话工厂SqlSessionFatory_需要给一个input流,这个流就是配置文件SqlMapConfig.xml
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(inputStream);

    // 创建会话SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 通过会话SqlSession使用sql语句查询
    // 源码中的方法<T> T selectOne(String statement, Object parameter);
    // 第一个参数:statement的id,前边要加namespace
    // 第二个参数:输入的参数对象值--此处创建一个User并赋值
    User user = new User();
    user.setId(36);
    user.setUsername("梅超风");
    user.setBirthday(new Date());
    user.setAddress("洛杉矶");

    // 添加用户
    int flag = sqlSession.update("test.updateUser", user);
    // 
    System.out.println(flag);

    // 提交
    sqlSession.commit();
    // 关闭session
    sqlSession.close();
}

结果如下:
这里写图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值