mybatis学习一:基于xml与注解配置入门实例与问题

注:本case参考自:http://www.cnblogs.com/ysocean/p/7277545.html

一:Mybatis的介绍:                                         

  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
  • iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。
  • MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。

二:基于xml配置的入门实例与介绍(idea的maven项目):                                            

1:case项目结构如图:(pom文件)

    mybatis学习一:基于xml与注解配置入门实例与问题

  几点注意:

    • 有可能idea下Maven项目会很卡,那么调整:Other Setting->default Setting->搜索maven->Runner中:VM Options设置为:-DarchetypeCatalog=internal;
    • main目录下的java使我们自己建的,要将java->右键->Mark Directory as设置为root(否则底下不能建立包文件);

  pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <!--
modelVersion:pom文件的模型版本
关于group id和artifact id,为了便于多人多模块协同开发管理(以后会讲),建议使用以下命名规范
group id:com.公司名.项目名
artifact id:功能模块名
packaging:项目打包的后缀,war是web项目发布用的,默认为jar
version:     artifact模块的版本
name和url:相当于项目描述,可删除
group id + artifact id +version :项目在仓库中的坐标
   -->
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.company.project</groupId>
    <artifactId>module</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>test Maven Webapp</name>
    <url>http://maven.apache.org</url>
  <!--上面这部分必须有-->

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!--<dependency>这里的jdbc的数据库连接jar总是报错,可以注释掉后从外部导入jar
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.7-bin</version>
        </dependency>-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>

2、创建数据库表:

 1 create database spring_mybatis_test1;
 2 use spring_mybatis_test1;
 3 create table user(
 4     id int(20) not null auto_increment,
 5     username varchar(50) ,
 6     sex varchar(10),
 7     birthday date,
 8     address varchar(100),
 9     primary key(id)
10 );

 向其中插入一条数据: insert into user(id,username,sex,birthday,address,) values(1,‘tom’,‘男’,'1993-05-25','earth'); 

补充:下面将要用到的配置参数:

  ①、parameterType:指定输入参数的类型

  ②、resultType:指定输出结果的类型,在select中如果查询结果是集合,那么也表示集合中每个元素的类型

  ③、#{}:表示占位符,用来接收输入参数,类型可以是简单类型,pojo,HashMap等等

    如果接收简单类型,#{}可以写成 value 或者其他名称

    如果接收 pojo 对象值,通过 OGNL 读取对象中的属性值,即属性.属性.属性...的方式获取属性值

  ④、${}:表示一个拼接符,会引起 sql 注入,不建议使用  

    用来接收输入参数,类型可以是简单类型,pojo,HashMap等等

    如果接收简单类型,${}里面只能是 value

    如果接收 pojo 对象值,通过 OGNL 读取对象中的属性值,即属性.属性.属性...的方式获取属性值

3:Mybatis的配置文件mybatis-configuration.xml:(事务,dataSource,userMapper.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>

    <!-- 注意:environments标签,当mybatis和spring整合之后,这个标签是不用配置的 -->

    <!-- 可以配置多个运行环境,但是每个 SqlSessionFactory 实例只能选择一个运行环境
      一、development:开发模式
       二、work:工作模式-->
    <environments default="development">
        <!--id属性必须和上面的default一样  -->
        <environment id="development">
            <!--事务管理器
                一、JDBC:这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围
                二、MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期
                    比如 spring 或 JEE 应用服务器的上下文,默认情况下,它会关闭连接。然而一些容器并不希望这样,
                    因此如果你需要从连接中停止它,就可以将 closeConnection 属性设置为 false,比如:
                    <transactionManager type="MANAGED">
                        <property name="closeConnection" value="false"/>
                    </transactionManager>
              -->
            <transactionManager type="JDBC"/>
            <!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源  -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/spring_mybatis_test1"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- 注册userMapper.xml文件,
        userMapper.xml位于com.ys.mapper这个包下,所以resource写成com/ys/mapper/userMapper.xml-->
        <mapper resource="mapping/userMapping.xml"/>
    </mappers>
</configuration>

4:实体类和映射文件userMapper.xml

  • 实体类User:
     1 package com.spring.model;
     2 
     3 import java.util.Date;
     4 public class User {
     5     private int id;
     6     private String username;
     7     private String sex;
     8     private Date birthday;
     9     private String address;
    10     public int getId() {
    11         return id;
    12     }
    13     public void setId(int id) {
    14         this.id = id;
    15     }
    16     public String getUsername() {
    17         return username;
    18     }
    19     public void setUsername(String username) {
    20         this.username = username;
    21     }
    22     public String getSex() {
    23         return sex;
    24     }
    25     public void setSex(String sex) {
    26         this.sex = sex;
    27     }
    28     public Date getBirthday() {
    29         return birthday;
    30     }
    31     public void setBirthday(Date birthday) {
    32         this.birthday = birthday;
    33     }
    34     public String getAddress() {
    35         return address;
    36     }
    37     public void setAddress(String address) {
    38         this.address = address;
    39     }
    40     @Override
    41     public String toString() {
    42         return "User [> sex
    43                 + ", birthday=" + birthday + ", address=" + address + "]";
    44     }
    45 }
    View Code
  • 映射文件:注意36-49行的自增主键获取
     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <!DOCTYPE mapper
     3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     5 <mapper namespace="user"><!--注意namespace的名称,测试文件中直接引用namespace-->
     6 
     7     <!-- 根据 id 查询 user 表中的数据
     8         id:唯一标识符,此文件中的id值不能重复
     9         resultType:返回值类型,一条数据库记录也就对应实体类的一个对象
    10         parameterType:参数类型,也就是查询条件的类型
    11    -->
    12     <select id="selectUserById"
    13             resultType="com.spring.model.User" parameterType="int">
    14         <!-- 这里和普通的sql 查询语句差不多,后面的 #{id}表示占位符,里面不一定要写id,写啥都可以,但是不要空着 -->
    15         select * from user where id = #{id}
    16     </select>
    17 
    18     <!-- 查询 user 表的所有数据
    19         注意:因为是查询所有数据,所以返回的应该是一个集合,这个集合里面每个元素都是User类型
    20      -->
    21     <select id="selectUserAll" resultType="com.spring.model.User">
    22         select * from user
    23     </select>
    24 
    25     <!-- 模糊查询:根据 user 表的username字段
    26             下面两种写法都可以,但是要注意
    27             1、${value}里面必须要写value,不然会报错
    28             2、${}表示拼接 sql 字符串,将接收到的参数不加任何修饰拼接在sql语句中
    29             3、使用${}会造成 sql 注入
    30      -->
    31     <select id="selectLikeUserName" resultType="com.spring.model.User" parameterType="String">
    32         select * from user where username like '%${value}%'
    33         <!-- select * from user where username like #{username} -->
    34     </select>
    35 
    36     <!-- 向 user 表插入一条数据 -->
    37     <insert id="insertUser" parameterType="com.spring.model.User">
    38         <!-- 将插入的数据主键返回到 user 对象中
    39              keyProperty:将查询到的主键设置到parameterType 指定到对象的那个属性
    40              select LAST_INSERT_ID():查询上一次执行insert 操作返回的主键id值,只适用于自增主键
    41              resultType:指定 select LAST_INSERT_ID() 的结果类型
    42              order:AFTER,相对于 select LAST_INSERT_ID()操作的顺序
    43          -->
    44         <selectKey keyProperty="id" resultType="int" order="AFTER">
    45             select LAST_INSERT_ID()
    46         </selectKey>
    47         insert into user(username,sex,birthday,address)
    48         value(#{username},#{sex},#{birthday},#{address})
    49     </insert>
    50 
    51     <!-- 根据 id 更新 user 表的数据 -->
    52     <update id="updateUserById" parameterType="com.spring.model.User">
    53         update user set username=#{username} where id=#{id}
    54     </update>
    55 
    56     <!-- 根据 id 删除 user 表的数据 -->
    57     <delete id="deleteUserById" parameterType="int">
    58         delete from user where id=#{id}
    59     </delete>
    60 </mapper>
      
  • 5:测试类:

      1 package com.ys.test;
      2  
      3 import java.io.InputStream;
      4 import java.util.List;
      5  
      6 import org.apache.ibatis.session.SqlSession;
      7 import org.apache.ibatis.session.SqlSessionFactory;
      8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
      9 import org.junit.Before;
     10 import org.junit.Test;
     11  
     14 public class CRUDTest {
     15     //定义 SqlSession
     16     SqlSession session =null;
     17      
     18     @Before
     19     public void init(){
     20         //定义mybatis全局配置文件
     21         String resource = "mybatis-configuration.xml";
     22         //加载 mybatis 全局配置文件
     23         InputStream inputStream = CRUDTest.class.getClassLoader().getResourceAsStream(resource);
     25         //构建sqlSession的工厂
     26         SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
     27         //根据 sqlSessionFactory 产生 session
     28         session = sessionFactory.openSession();
     29     }
     30      
     31     //根据id查询user表数据
     32     @Test
     33     public void testSelectUserById(){
     34         /*这个字符串由 userMapper.xml 文件中 两个部分构成
     35             <mapper namespace="user"> 的 namespace 的值
     36             <select >*/
     37         String statement = "user.selectUserById";
     38         User user = session.selectOne(statement, 1);
     39         System.out.println(user);
     40         session.close();
     41     }
     42      
     43     //查询所有user表所有数据
     44     @Test
     45     public void testSelectUserAll(){
     46         String statement = "user.selectUserAll";
     47         List<User> listUser = session.selectList(statement);
     48         for(User user : listUser){
     49             System.out.println(user);
     50         }
     51         session.close();
     52     }
     53      
     54     //模糊查询:根据 user 表的username字段
     55     @Test
     56     public void testSelectLikeUserName(){
     57         String statement = "user.selectLikeUserName";
     58         List<User> listUser = session.selectList(statement, "%t%");
     59         for(User user : listUser){
     60             System.out.println(user);
     61         }
     62         session.close();
     63          
     64     }
     65     //向 user 表中插入一条数据
     66     @Test
     67     public void testInsertUser(){
     68         String statement = "user.insertUser";
     69         User user = new User();
     70         user.setUsername("Bob");
     71         user.setSex("女");
     72         session.insert(statement, user);
     73         //提交插入的数据
     74         session.commit();
     75         session.close();
     76     }
     77      
     78     //根据 id 更新 user 表的数据
     79     @Test
     80     public void testUpdateUserById(){
     81         String statement = "user.updateUserById";
     82         //如果设置的 id不存在,那么数据库没有数据更改
     83         User user = new User();
     84         user.setId(4);
     85         user.setUsername("jim");
     86         session.update(statement, user);
     87         session.commit();
     88         session.close();
     89     }   
     91  
     92     //根据 id 删除 user 表的数据
     93     @Test
     94     public void testDeleteUserById(){
     95         String statement = "user.deleteUserById";
     96         session.delete(statement,4);
     97         session.commit();
     98         session.close();
     99     }
    100 }

    结果:以下我只测试了testSelectUserById和testSelectLikeUserName,两个是一样的: User [id=1, username=tom, sex=男, birthday=Tue May 25 00:00:00 CST 1993, address=earth] 。

    6:获取主键值:

    • 数据库有自增主键:映射配置中的36-49行
       1 <!-- 向 user 表插入一条数据 -->
       2     <insert id="insertUser" parameterType="com.ys.po.User">
       3         <!-- 将插入的数据主键返回到 user 对象中
       4              keyProperty:将查询到的主键设置到parameterType 指定到对象的那个属性
       5              select LAST_INSERT_ID():查询上一次执行insert 操作返回的主键id值,只适用于自增主键
       6              resultType:指定 select LAST_INSERT_ID() 的结果类型
       7              order:AFTER,相对于 select LAST_INSERT_ID()操作的顺序
       8          -->
       9         <selectKey keyProperty="id" resultType="int" order="AFTER">
      10             select LAST_INSERT_ID()
      11         </selectKey>
      12         insert into user(username,sex,birthday,address)
      13             value(#{username},#{sex},#{birthday},#{address})
      14     </insert>
    • 非自增主键:
       1 <!-- 向 user 表插入一条数据 -->
       2     <insert id="insertUser" parameterType="com.ys.po.User">
       3         <!-- 将插入的数据主键返回到 user 对象中
       4         流程是:首先通过 select UUID()得到主键值,然后设置到 user 对象的id中,在进行 insert 操作
       5              keyProperty:将查询到的主键设置到parameterType 指定到对象的那个属性
       6              select UUID():得到主键的id值,注意这里是字符串
       7              resultType:指定 select UUID() 的结果类型
       8              order:BEFORE,相对于 select UUID()操作的顺序
       9          -->
      10         <selectKey keyProperty="id" resultType="String" order="BEFORE">
      11             select UUID()
      12         </selectKey>
      13         insert into user(id,username,sex,birthday,address)
      14             value(#{id},#{username},#{sex},#{birthday},#{address})
      15     </insert>

    三:基于注解配置的入门实例与介绍(idea的maven项目):                              

    1:我们直接在上面的case中配置注解方式,整个目录结构如下:   

      mybatis学习一:基于xml与注解配置入门实例与问题

    需要改动的地方包括以上三个部分:

    2:不需要动的部分       

    • pom.xml不需要改动;
    • User实体bean不需要改动;
    • userMapping.xml弃用

    3、定义操作user表的注解接口UserMapper.java(接口)     

     1 package com.spring.model;
     2 
     3 import org.apache.ibatis.annotations.Delete;
     4 import org.apache.ibatis.annotations.Insert;
     5 import org.apache.ibatis.annotations.Select;
     6 import org.apache.ibatis.annotations.Update;
     7 
     8 public interface UserMapper {
     9 
    10     //根据 id 查询 user 表数据
    11     @Select("select * from user where id=#{id}")
    12     public User selectUserById(int id) throws  Exception;
    13 
    14     //箱user插入一条数据
    15     @Insert("insert into user(username,sex,birthday,address) values(#{username},#{sex},#{birthday},#{address})")
    16     public void insertUser(User user) throws Exception;
    17 
    18     //根据 id 修改 user 表数据
    19     @Update("update user set username=#{username},sex=#{sex} where id=#{id}")
    20     public void updateUserById(User user) throws Exception;
    21 
    22     //根据 id 删除 user 表数据
    23     @Delete("delete from user where id=#{id}")
    24     public void deleteUserById(int id) throws Exception;
    25 }

    4、mybatis-configuration.xml中注册映射接口UserMapper.java   

    1 ......
    2 <mappers>
    3     <!-- xml方式,注册userMapper.xml文件,
    4     userMapper.xml位于com.ys.mapper这个包下,所以resource写成com/ys/mapper/userMapper.xml
    5     <mapper resource="mapping/userMapping.xml"/>-->
    6     <mapper class="com.spring.model.UserMapper"></mapper>
    7 </mappers>

    5、创建测试类  

     1 package com.spring;
     2 
     3 import com.spring.CRUDTest;
     4 import com.spring.model.User;
     5 import com.spring.model.UserMapper;
     6 import org.apache.ibatis.session.SqlSession;
     7 import org.apache.ibatis.session.SqlSessionFactory;
     8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     9 import org.junit.Before;
    10 import org.junit.Test;
    11 
    12 import java.io.InputStream;
    13 
    14 public class TestAnnotationCRUD {
    15     SqlSession session=null;
    16 
    17     @Before
    18     public void init(){
    19         //定义mybatis全局配置文件
    20         String resource = "mybatis-configuration.xml";
    21         //加载 mybatis 全局配置文件
    22         InputStream inputStream = CRUDTest.class.getClassLoader().getResourceAsStream(resource);
    23         //构建sqlSession的工厂
    24         SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    25         //根据 sqlSessionFactory 产生 session
    26         session = sessionFactory.openSession();
    27     }
    28 
    29     //注解的增删改查方法测试
    30     @Test
    31     public void testAnncationCRUD() throws Exception {
    32         //根据session获取 UserMapper接口
    33         UserMapper userMapper = session.getMapper(UserMapper.class);
    34         //调用selectUserById()方法
    35         User user = userMapper.selectUserById(1);
    36         System.out.println(user);
    37 
    38         //调用  insertUser() 方法
    39         User user1 = new User();
    40         user1.setUsername("aliks");
    41         user1.setSex("不详");
    42         userMapper.insertUser(user1);
    43 
    44         //调用 updateUserById() 方法
    45         User user2 = new User();
    46         user2.setId(6);
    47         user2.setUsername("lbj");
    48         userMapper.updateUserById(user2);
    49 
    50         //调用 () 方法
    51         userMapper.deleteUserById(6);
    52 
    53         session.commit();
    54         session.close();
    55     }
    56 
    57

    idea输出: User [id=1, username=tom, sex=男, birthday=Tue May 25 00:00:00 CST 1993, address=earth] 

    数据库结果:

    mybatis学习一:基于xml与注解配置入门实例与问题

    注解配置使我们放弃了映射文件mapping.xml,需要接口实现数据库操作与到方法间的映射