MyBatis学习笔记

MyBatis简介

  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程
    进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • 原理:Mybatis 通过 l xml 或注解的方式将要执行的各种 statement(statement、preparedStatemntCallableStatement)配置起来,
    并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由 mybatis 框架执行 sql 并将结果映射成 java 对象并返回。

MyBatis的框架核心

  • mybatis 配置文件,包括Mybatis 全局配置文件和 Mybatis 映射文件,其中全局配置文件,配置了数据源、事务等信息;映射文件配置了 SQL 执行相关的 信息。
  • mybatis 通过读取配置文件信息(全局配置文件和映射文件),构造出 SqlSessionFactory,即会话工厂
  • 通过 SqlSessionFactory,可以创建SqlSession即会话。Mybatis 是通过 SqlSession 来操作数据库的。
  • SqlSession 本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
  • Executor 执行器要处理的 SQL 信息是封装到一个底层对象MappedStatement中。该对象包括:SQL 语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括HashMap集合对象、POJO 对象类型

MyBatis入门

环境准备

  • 创建数据库表

    /*Table structure for table `items` */
    CREATE TABLE items (
      id int(11) NOT NULL AUTO_INCREMENT,
      name varchar(32) NOT NULL COMMENT '商品名称',
      price float(10,1) NOT NULL COMMENT '商品定价',
      detail text COMMENT '商品描述',
      pic varchar(64) DEFAULT NULL COMMENT '商品图片',
      createtime datetime NOT NULL COMMENT '生产日期',
      PRIMARY KEY (id)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    /*Table structure for table `user` */
    CREATE TABLE user (
      id int(11) NOT NULL AUTO_INCREMENT,
      username varchar(32) NOT NULL COMMENT '用户名称',
      birthday date DEFAULT NULL COMMENT '生日',
      sex char(1) DEFAULT NULL COMMENT '性别',
      address varchar(256) DEFAULT NULL COMMENT '地址',
      PRIMARY KEY (id)
    ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
    
    /*Table structure for table `orders` */
    CREATE TABLE orders (
      id int(11) NOT NULL AUTO_INCREMENT,
      user_id int(11) NOT NULL COMMENT '下单用户id',
      number varchar(32) NOT NULL COMMENT '订单号',
      createtime datetime NOT NULL COMMENT '创建订单时间',
      note varchar(100) DEFAULT NULL COMMENT '备注',
      PRIMARY KEY (id),
      KEY FK_orders_1 (user_id),
      CONSTRAINT FK_orders_id FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
    
    /*Table structure for table `orderdetail` */
    CREATE TABLE orderdetail (
      id int(11) NOT NULL AUTO_INCREMENT,
      orders_id int(11) NOT NULL COMMENT '订单id',
      items_id int(11) NOT NULL COMMENT '商品id',
      items_num int(11) DEFAULT NULL COMMENT '商品购买数量',
      PRIMARY KEY (id),
      KEY FK_orderdetail_1 (orders_id),
      KEY FK_orderdetail_2 (items_id),
      CONSTRAINT FK_orderdetail_1 FOREIGN KEY (orders_id) REFERENCES orders (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
      CONSTRAINT FK_orderdetail_2 FOREIGN KEY (items_id) REFERENCES items (id) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
    
  • 向表中插入数据

    insert  into items(id,name,price,detail,pic,createtime) values (1,'台式机',3000.0,'该电脑质量非常好!!!!',NULL,'2015-02-03 13:22:53'),(2,'笔记本',6000.0,'笔记本性能好,质量好!!!!!',NULL,'2015-02-09 13:22:57'),(3,'背包',200.0,'名牌背包,容量大质量好!!!!',NULL,'2015-02-06 13:23:02');
    
    insert  into user(id,username,birthday,sex,address) values (1,'王五',NULL,'2',NULL),(10,'张三','2014-07-10','1','北京市'),(16,'张小明',NULL,'1','河南郑州'),(22,'陈小明',NULL,'1','河南郑州'),(24,'张三丰',NULL,'1','河南郑州'),(25,'陈小明',NULL,'1','河南郑州'),(26,'王五',NULL,NULL,NULL);
    
    insert  into orders(id,user_id,number,createtime,note) values (3,1,'1000010','2015-02-04 13:22:35',NULL),(4,1,'1000011','2015-02-03 13:22:41',NULL),(5,10,'1000012','2015-02-12 16:13:23',NULL);
    
    insert  into orderdetail(id,orders_id,items_id,items_num) values (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3);
    
  • 创建项目并导包

    asm-3.3.1.jar
    cglib-2.2.2.jar
    commons-logging-1.1.1.jar
    javassist-3.17.1-GA.jar
    log4j-1.2.17.jar
    log4j-api-2.0-rc1.jar
    log4j-core-2.0-rc1.jar
    mybatis-3.2.7.jar
    mysql-connector-java-5.1.7-bin.jar
    slf4j-api-1.7.5.jar
    slf4j-log4j12-1.7.5.jar
    

    并在src目录下创建log4j.properties文件

    # Global logging configuration
    log4j.rootLogger=DEBUG, stdout
    # 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
    #日志级别在开发阶段设置成DEBUG
    #在生产阶段设置成INFO或者ERROR
    

全局配置文件和映射文件配置

  • 开发步骤

    • 创建PO(model)类,根据需求创建;

    • 创建全局配置文件SqlMapConfig.xml

    • 编写映射文件

    • 加载映射文件,在SqlMapConfig.xml中进行加载

    • 编写测试程序,即编写java代码,连接并操作数据库

      思路:

      • 读取配置文件
      • 通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
      • 通过SqlSessionFactory创建SqlSession
      • 调用SqlSession的操作数据库方法。
      • 关闭SqlSession
  • 创建SqlMapConfig.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>
        <!-- 配置 mybatis 的环境信息 -->
        <environments default="development">
            <environment id="development">
                <!-- 配置 JDBC 事务控制,由 mybatis 进行管理 -->
                <transactionManager type="JDBC"></transactionManager>
                <!-- 配置数据源,采用 dbcp 连接池 -->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url"
                              value="jdbc:mysql://localhost:3306/spring_day3?useUnicode=true&amp;characterEncoding=utf8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
    </configuration>
    
  • 映射文件

    <?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:命名空间,它的作用就是对 SQL 进行分类化管理,可以理解为 SQL 隔离
    注意:使用 mapper 代理开发时,namespace 有特殊且重要的作用
    -->
    <mapper namespace="test">
    <!--
    [id]:statement 的 id,要求在命名空间内唯一
    [parameterType]:入参的 java 类型
    [resultType]:查询出的单条结果集对应的 java 类型
    [#{}]: 表示一个占位符?
    [#{id}]:表示该占位符待接收参数的名称为 id。注意:如果参数为简单类型时,#{}里面的参数名称可以
    是任意定义
    -->
    	<select id="findUserById" parameterType="int" 						  resultType="com.gyf.domain.User">
    		SELECT * FROM USER WHERE id = #{id}
    	</select>
    </mapper>
    
  • 测试类

    package test;
    
    import model.User;
    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 java.io.IOException;
    import java.io.InputStream;
    
    public class one {
        @Test
        public void test() throws IOException {
            //获取全局配置文件路径并读取
            String resource = "SqlMapConfig.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            //通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
            SqlSessionFactory sessionFactory =
                    new SqlSessionFactoryBuilder().build(is);
            //通过SqlSessionFactory创建SqlSession
            SqlSession session = sessionFactory.openSession();
            //调用SqlSession的操作数据库方法
            User user = session.selectOne("findUserById", 10);
            System.out.println(user.toString());
            //关闭SqlSession
            session.commit();
        }
    }
    

基础查询讲解

注意:增删改后要提交事务

模糊查询讲解

  • 映射文件配置

    <?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="test">
    <!--
    	[${}]:表示拼接 SQL 字符串
    	[${value}]:表示要拼接的是简单类型参数。
    	注意:
    	1、如果参数为简单类型时,${}里面的参数名称必须为 value
    	2、${}会引起 SQL 注入,一般情况下不推荐使用。但是有些场景必须使用${},比	     如 order by ${colname}
    -->
        <select id="findUserByName" parameterType="String" resultType="model.User">
            SELECT * FROM USER WHERE username like '%${value}%';
        </select>
    </mapper>
    
  • 测试类

    //简写
    List<User> user = session.selectList("findUserByName", "张");
    for (User res : user) {
         System.out.println(res.toString());
    }
    

插入用户信息

  • 映射文件配置

    <insert id="insertUser" parameterType="model.User">
            INSERT INTO USER (username,sex,birthday,address)
            VALUES(#{username},#{sex},#{birthday},#{address})
    </insert>
    
  • 测试类

    session.insert("insertUser",
                    new User("cyh", "男", new Date(), "安徽省合肥市"));
    

删除用户信息

  • 映射文件配置

    <delete id="deleteById" parameterType="int">
            DELETE FROM USER WHERE id = #{id};
    </delete>
    
  • 测试类

    session.delete("deleteById",27);
    

更新用户

  • 映射文件配置

    <update id="updateUser" parameterType="model.User">
            UPDATE USER SET username=#{username},sex=#{sex}
            WHERE id=#{id};
    </update>
    
  • 测试类

    User user = new User();
    user.setId(1);
    user.setUsername("蔡宇浩");
    user.setSex("男");
    session.update("updateUser",user);
    

主键返回之Mysql自增主键

思路

  • Mysql自增主键,是指在insert之前Mysql会自动生成一个自增的主键。

  • 我们可以通过Mysql的函数获取到刚插入的自增主键:LAST_INSERT_ID()

  • 这个函数是在insert语句之后去调用。

  • 映射文件配置

    <insert id="autoInsertUser" parameterType="model.User">
        <!--
    		[selectKey 标签]:通过 select 查询来生成主键
    		[keyProperty]:指定存放生成主键的属性
    		[resultType]:生成主键所对应的 Java 类型
    		[order]:指定该查询主键 SQL 语句的执行顺序,相对于 insert 语句
    		[last_insert_id]:MySQL 的函数,要配合 insert 语句一起使用 -->
            <selectKey keyProperty="id" resultType="int" order="AFTER">
                SELECT LAST_INSERT_ID()
            </selectKey>
        <!--如果主键的值是通过Mysql自增机制生成的,那么我们此处不需要给ID赋值-->
            INSERT INTO user (username,sex,birthday,address)
        	VALUES(#{username},#{sex},#{birthday},#{address});
    </insert>
    

小结

parameterType和resultType
parameterType指定输入参数的java类型,可以填写别名或Java类的全限定名。
resultType指定输出结果的java类型,可以填写别名或Java类的全限定名。
#{} 和 ${}
#{}:相当于预处理中的占位符?。
#{}里面的参数表示接收java输入参数的名称。
#{}可以接受 HashMap、POJO类型的参数。
当接受简单类型的参数时,#{}里面可以是 value,也可以是其他。
#{}可以防止 SQL 注入。
${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。
${}会引起SQL注入所以要谨慎使用。
${}可以接受HashMap、POJO类型的参数。
当接受简单类型的参数时,${}里面只能是 value。
selectOne和selectList
selectOne:只能查询0或1条记录,大于1条记录的话,会报错:
selectList:可以查询0或N条记录。

MyBatis的Dao编写【手动】

注意不推荐使用这种方法,MyBatis可以有多种其他实现方式。

  • dao层

    //UserDao(接口)
    package dao;
    
    import model.User;
    
    public interface UserDao {
        public void save(User user);
        public User findUserById(int id);
    }
    //UserDaoImpl(实现类)
    package dao;
    
    import model.User;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    public class UserDaoImpl implements UserDao {
        //注入SessionFactory
        private SqlSessionFactory ssf;
    
        /**
         * 注入SqlSessionFactory
         */
        public void setSsf(SqlSessionFactory ssf) {
            this.ssf = ssf;
        }
    
        public UserDaoImpl(SqlSessionFactory ssf) {
            super();
            this.ssf = ssf;
        }
    
        @Override
        public void save(User user) {
            SqlSession session = ssf.openSession();
            session.insert("insertUser",user);
            session.commit();
            session.close();
        }
    
        @Override
        public User findUserById(int id) {
            SqlSession session = ssf.openSession();
            User user = session.selectOne("findUserById", id);
            session.close();
            return user;
        }
    }
    
  • 测试

    package test;
    
    import dao.UserDao;
    import dao.UserDaoImpl;
    import model.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.InputStream;
    
    public class two {
        SqlSessionFactory ssf;
        @Before //在test测试方法前执行setup方法
        public void setup() throws Exception{
            //1.读取配置文件
            InputStream is =
                    Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.通过SqlSessionFactoryBuilder创建
            // SqlSessionFactory会话工厂
            ssf = new SqlSessionFactoryBuilder().build(is);
        }
        @Test
        public void test(){
            UserDao userDao = new UserDaoImpl(ssf);
            //保存用户
            User user = new User();
            user.setId(32);
            user.setUsername("辣鸡");
            userDao.save(user);
            System.out.println(user.toString());
            //查找用户
            User u = userDao.findUserById(10);
            System.out.println(u.toString());
        }
    }
    

MyBatis的Dao编写【mapper代理方式实现】

  • Mapper代理的开发方式,程序员只需要编写mapper接口(相当于dao接口)即可。MyBatis会自动的为mapper接口生成动态代理实现类。
  • 不过要实现mapper代理的开发方式,需要遵循一些开发规范。
  • 开发规范
    • mapper接口的全限定名要和mapper映射文件的namespace的相同。
    • mapper接口的方法名称要和mapper映射文件中的statementid相同。
    • mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
    • mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致。
    • 通过规范式的开发mapper接口,可以解决原始dao开发当中存在的问题
    • 模板代码已经去掉。
    • 剩下去不掉的操作数据库的代码,其实就是一行代码。这行代码中硬编码的部分,通过第一和第二个规范就可以解决。

编写步骤

  • 第一步:编写mapper接口

    重新写个 UserMapper 配置文件和定义 mapper 映射文件
    UserMapper.xml(内容同 Users.xml, 除了 namespace 的值),
    放到新创建的目录 mapper 下。

    package mapper;
    
    import model.User;
    
    public interface UserMapper {
        public void save(User user);
        public User findUserById(int id);
    }
    
    <?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="mapper.UserMapper">
        <select id="findUserById" parameterType="int" resultType="model.User">
            SELECT * FROM USER WHERE id=#{?};
        </select>
        <insert id="save" parameterType="model.User">
            <selectKey keyProperty="id" resultType="int" order="AFTER">
                SELECT LAST_INSERT_ID();
            </selectKey>
            INSERT INTO USER (id,username,sex,birthday,address)
            VALUES(#{id},#{username},#{sex},#{birthday},#{address})
        </insert>
    </mapper>
    
  • 第二步:添加映射配置文件

    <!--在SqlMapConfig.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>
        <!-- 配置 mybatis 的环境信息 -->
        <environments default="development">
            <environment id="development">
                <!-- 配置 JDBC 事务控制,由 mybatis 进行管理 -->
                <transactionManager type="JDBC"></transactionManager>
                <!-- 配置数据源,采用 dbcp 连接池 -->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url"
                              value="jdbc:mysql://localhost:3306/spring_day3?useUnicode=true&amp;characterEncoding=utf8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <!--告诉mybatis加载映射文件-->
        <mappers>
            <mapper resource="mapper/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  • 第三步:测试

    package test;
    
    import mapper.UserMapper;
    import model.User;
    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.Before;
    import org.junit.Test;
    
    import java.io.InputStream;
    import java.util.Date;
    
    public class three {
        SqlSessionFactory ssf;
        //加载配置文件
        @Before
        public void setup()throws Exception{
            InputStream is =
                    Resources.getResourceAsStream("SqlMapConfig.xml");
            ssf = new SqlSessionFactoryBuilder().build(is);
        }
        @Test
        public void test(){
            SqlSession session = ssf.openSession();
            //通过session获取代理【JDK实现的代理】
            UserMapper mapper = session.getMapper(UserMapper.class);
            //保存用户
            User user = new User();
            user.setUsername("赵佳");
            user.setSex("女");
            user.setBirthday(new Date());
            user.setAddress("上海市");
            mapper.save(user);
            System.out.println(user.toString());
            session.commit();
            //查找用户
            User u = mapper.findUserById(48);
            System.out.println(u.toString());
            session.close();
        }
    }
    

全局配置文件其他配置

properties数据库文件配置及使用
  • 在src下配置个db.properties文件

    driverClass=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/spring_day3?useUnicode=true&amp;characterEncoding=utf8
    username=root
    password=123456
    
  • 修改全局的配置文件

    <?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"/>
        <!--配置mybatis的环境信息-->
        <environments default="development">
            <environment id="development">
                <!--配置JDBC事务控制,由mybatis进行管理-->
                <transactionManager type="JDBC"></transactionManager>
                <!--配置数据源,采用dbcp连接池-->
                <dataSource type="POOLED">
                    <!--使用${},可以引用已经加载的java配置文件中的信息-->
                    <property name="driver" value="${driverClass}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <!--告诉mybatis加载映射文件-->
        <mappers>
            <mapper resource="mapper/UserMapper.xml"/>
        </mappers>
    </configuration>
    
typeAliases(别名的使用)

​ 别名的使用时为了在映射文件中,更方便的去指定参数和结果集的类型,不再用写很长的一 段全限定名。

mybatis支持的别名
别名映射的类型别名映射的类型别名映射的类型
_bytebyte_longlong_shortshort
_intint_integerint_doubledouble
_floatfloat_booleanbooleanstringString
byteBytelongLongshortShort
intIntegerintegerIntegerdoubleDouble
floatFloatbooleanBooleandateDate
decimalBigDecimalbigdecimalBigDecimal
自定义别名
  • SqlMapConfig.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文件的引用一定要放在前面-->
        <properties resource="db.properties"/>
        <!--别名配置-->
        <typeAliases>
            <!--单个定义别名-->
            <typeAlias type="model.User" alias="user"/>
            <!--批量配置别名-->
            <!--[name]:
             指定批量定义别名的类型,别名为类名,第一个小写
        </typeAliases>
        <!--配置mybatis的环境信息-->
        <environments default="development">
            <environment id="development">
                <!--配置JDBC事务控制,由mybatis进行管理-->
                <transactionManager type="JDBC"></transactionManager>
                <!--配置数据源,采用dbcp连接池-->
                <dataSource type="POOLED">
                    <!--使用${},可以引用已经加载的java配置文件中的信息-->
                    <property name="driver" value="${driverClass}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <!--告诉mybatis加载映射文件-->
        <mappers>
            <mapper resource="mapper/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  • 实际的实现类文件中,resultType和parameterType若用到上述别名,可直接引用,不再需要写全名。

mappers
  • 使用相对于类路径的资源
    如:

  • 【不用】

    使用完全限定路径

  • 使用 mapper 接口的全限定名
    如:

    也可使用注解开发,把 xml 文件删除

    注意 :此种方法要求 mapper 接口和 mapper 映射文件要名称相同,
    且放到同一个目录下;

  • 推荐

    注册指定包下的所有映射文件(只到包名
    如:
    注意 :此种方法要求 mapper 接口和 mapper 映射文件要名称相同,
    且放到同一个目录下;

MyBatis的映射文件

输入映射ParameterType

指定输入参数的Java类型,可以使用别名或者类的全限定名,它可以接收简单类型POJO对象HashMap

  • 传递简单类型

SELECT * FROM USER WHERE id = #{id}; ```
  • 传递POJO对象

    <insert id="save" parameterType="user">
            <selectKey keyProperty="id" resultType="int" order="AFTER">
                SELECT LAST_INSERT_ID();
            </selectKey>
            INSERT INTO USER (id,username,sex,birthday,address)
            VALUES(#{id},#{username},#{sex},#{birthday},#{address})
    </insert>
    
  • 传递POJO包装对象

    //定义POJO包装类
    package vo;
    import model.User;
    
    public class UserQueryVO {
        private User user;
        public User getUser() {
            return user;
        }
        public void setUser(User user) {
            this.user = user;
        }
    }
    //修改UserMapper.java
    package mapper;
    import model.User;
    import vo.UserQueryVO;
    import java.util.List;
    
    public interface UserMapper {
        public void save(User user);
        public User findUserById(int id);
        public List<User> findUserByVo(UserQueryVO vo);
    }
    
    <!--修改UserMapper.xml-->
    <select id="findUserByVo" parameterType="vo.UserQueryVO" resultType="user">
            SELECT u.* FROM user u WHERE u.id = #{user.id}
    </select>
    
  • 传递Map对象

    //UserMapper.java
    package mapper;
    
    import model.User;
    import vo.UserQueryVO;
    
    import java.util.List;
    import java.util.Map;
    
    public interface UserMapper {
        public void save(User user);
        public User findUserById(int id);
        public List<User> findUserByVo(UserQueryVO vo);
        public List<User> findUserListByMap(Map<String,Object> map);
    }
    
    <!--修改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">
    <mapper namespace="mapper.UserMapper">
        <select id="findUserListByMap" parameterType="hashmap" resultType="user">
            SELECT * FROM USER WHERE sex=#{sex} AND username=#{username};
        </select>
    </mapper>
    
    //测试
    package test;
    
    import mapper.UserMapper;
    import model.User;
    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.Before;
    import org.junit.Test;
    import vo.UserQueryVO;
    import java.io.InputStream;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class four {
        SqlSessionFactory ssf;
        @Before
        public void setup()throws Exception{
            InputStream is =
                    Resources.getResourceAsStream("SqlMapConfig.xml");
            ssf = new SqlSessionFactoryBuilder().build(is);
        }
        @Test
        public void test1(){
            SqlSession session = ssf.openSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("sex","男");
            map.put("username","cyh");
            List<User> list = mapper.findUserListByMap(map);
            System.out.println(list);
            session.close();
        }
    }
    

输出映射 resultType/resultMap

  • 同输入映射规则一致,不详细解说。

动态SQL

if和where

  • if标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。

    ==注意:==用if进行判断是否为空时,不仅要判断null,也要判断空字符串。

  • where标签:会去掉条件中的第一个and符号。

    <select id="findUserList" parameterType="vo.UserQueryVO" resultType="user">
            SELECT * FROM user
            <where>
                <if test="user != null">
                    <if test="user.sex != null and user.sex != ''">
                        sex=#{user.sex}
                    </if>
                    <if test="user.username != null and user.username != ''">
                        AND username LIKE '%${user.username}%'
                    </if>
                </if>
            </where>
    </select>
    

SQL片段

MyBatis提供了SQL片段的功能,可以提高SQL的可重用性。

<!--声明一个SQL片段-->
    <sql id="select_user_where">
        <if test="user != null">
            <if test="user.sex != null and user.sex != ''">
                sex=#{user.sex}
            </if>
            <if test="user.username != null and user.username != ''">
                AND username LIKE '%${user.username}%'
            </if>
        </if>
    </sql>
    <select id="findUserList" parameterType="vo.UserQueryVO" resultType="user">
        SELECT * FROM USER
        <where>
            <!--引用SQL片段-->
            <include refid="select_user_where"/>
        </where>
    </select>

foreach遍历

案例:查询指定id的用户

select * from user where id in (64,65,66);
//定义包装类
package vo;

import model.User;

import java.util.List;

//定义查询包装类,以后.xml的参数从这个对象取
public class UserListQuery {
    private User user;
    private List<Integer> ids;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<Integer> getIds() {
        return ids;
    }

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }
}
<!--UserMapper.xml-->
<select id="findListUser" parameterType="vo.UserListQuery" resultType="user">
     SELECT * FROM USER
     <where>
         <if test="ids != null and ids.size > 0">
             <!--
			collection:集合,写集合属性
			item:遍历接收变量
			open:遍历开始
			close:遍历结束
			separator:拼接格式
			-->
             <foreach collection="ids" item="id" open="AND id in(" close=")" separator=",">
                 ${id}
             </foreach>
         </if>
     </where>
</select>
//测试类
@Test
    public void test4(){
        SqlSession session = ssf.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        UserListQuery ulq = new UserListQuery();
        List<Integer> list = new ArrayList<Integer>();
        list.add(64);
        list.add(65);
        list.add(66);
        ulq.setIds(list);
        System.out.println(mapper.findListUser(ulq));
        session.close();
    }

另一种遍历,参数直接传入id集合

<select id="findListUser" parameterType="java.util.List" resultType="user">
        SELECT * FROM USER
        <where>
            <!--如果是直接传入集合参数,则该处的参数名称只能填写list-->
            <if test="list != null and list.size > 0">
                <foreach collection="list" item="id" open="AND id IN (" close=")" separator=",">
                    #{id}
                </foreach>
            </if>
        </where>
</select>
//测试类
@Test
    public void test4(){
        SqlSession session = ssf.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<Integer> list = new ArrayList<Integer>();
        list.add(10);
        list.add(16);
        list.add(22);
        System.out.println(mapper.findListUser(list));
        session.close();
    }

MyBatis与Hibernate的区别【面试题】

MyBatis技术特点:

好处

  • 通过直接编写SQL语句,可以直接对SQL进行性能的优化。
  • 学习门槛低,学习成本低。只要有SQL基础,就可以学习MyBatis,而且很容易上手。
  • 由于直接编写SQL语句,所以灵活多变,代码维护性更好。

缺点

  • 不能支持数据库无关性,即数据库发生变更,要写多套代码进行支持,移植性不好。
  • 需要编写结果映射。

Hibernate技术特点:

好处

  • 标准的ORM框架,程序员不需要编写SQL语句。
  • 具有良好的数据库无关性,即数据库发生变化的话,代码无需再次编写。

缺点

  • 学习门槛高,需要对数据关系模型有良好的基础,而且在设置OR映射的时候,需要考虑好性能和对象模型的权衡。
  • 程序员不能自主的去进行SQL性能优化。

MyBatis应用场景:

需求多变的互联网项目,例如电商项目。

Hibernate应用场景:

需求明确,业务固定的项目,例如OA项目、ERP项目等。

关联查询

一对一 resultType实现(扩展类实现

复杂查询时,单表对应的po类已不能满足输出结果集的映射。所以要根据需求建立一个扩展类来作为resultType的类型.

例子

查找某个订单id的信息,包括用户名字和地址。

  • 第一步:写个订单的扩展类

    //订单类
    package model;
    
    import java.util.Date;
    
    public class Orders {
        private Integer id;
        private Integer user_id;
        private String note;
        private String number;
        private Date createtime;
    
        public Orders() {
        }
    
        public Orders(Integer id, Integer user_id, String note, String number, Date createtime) {
            this.id = id;
            this.user_id = user_id;
            this.note = note;
            this.number = number;
            this.createtime = createtime;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public Integer getUser_id() {
            return user_id;
        }
    
        public void setUser_id(Integer user_id) {
            this.user_id = user_id;
        }
    
        public String getNote() {
            return note;
        }
    
        public void setNote(String note) {
            this.note = note;
        }
    
        public String getNumber() {
            return number;
        }
    
        public void setNumber(String number) {
            this.number = number;
        }
    
        public Date getCreatetime() {
            return createtime;
        }
    
        public void setCreatetime(Date createtime) {
            this.createtime = createtime;
        }
    
        @Override
        public String toString() {
            return "Orders{" +
                    "id=" + id +
                    ", user_id=" + user_id +
                    ", note='" + note + '\'' +
                    ", number='" + number + '\'' +
                    ", createtime=" + createtime +
                    '}';
        }
    }
    //订单扩展类
    package model;
    
    import java.util.Date;
    
    public class OrdersExt extends Orders{
        private String username;
        private String address;
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "OrdersExt{" +
                    "username='" + username + '\'' +
                    ", address='" + address + '\'' +
                    '}'+super.toString();
        }
    }
    
  • 第二步:声明订单接口

    package mapper;
    
    import model.OrdersExt;
    
    public interface OrderMapper {
        public OrdersExt findOrderById(int id);
    }
    
  • 第三步:声明订单配置文件

    <?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="mapper.OrderMapper">
        <select id="findOrderById" parameterType="int" resultType="model.OrdersExt">
            select
                o.*,u.username,u.address
            from
                orders o ,user u
            where
                o.user_id = u.id
                and u.id= #{id};
        </select>
    </mapper>
    
  • 第四步:加载映射文件

    <!--告诉mybatis加载映射文件-->
        <mappers>
            <package name="mapper"/>
        </mappers>
    
  • 第五步:测试

    package test;
    
    import mapper.OrderMapper;
    import model.OrdersExt;
    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.Before;
    import org.junit.Test;
    
    import java.io.InputStream;
    
    public class one {
        SqlSessionFactory ssf;
        @Before
        public void setup()throws Exception{
            InputStream is =
                    Resources.getResourceAsStream("SqlMapConfig.xml");
            ssf = new SqlSessionFactoryBuilder().build(is);
        }
        @Test
        public void test(){
            SqlSession session = ssf.openSession();
            OrderMapper mapper = session.getMapper(OrderMapper.class);
            OrdersExt res = mapper.findOrderById(10);
            System.out.println(res);
            session.close();
        }
    }
    

一对一 resultMap实现(模型里有模型)

//OrdersMapper.java 添加一个方法
//根据订单id查询订单信息
public Orders findOrderByRslMap(int id);
<!--在OrdersMapper.xml中加入配置信息-->
<resultMap id="orderRslMap" type="model.Orders">
        <result column="id" property="id"/>
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>
        <!--关联内部对象-->
        <association property="user" javaType="domain.User">
            <id column="user_id" property="id"/>
            <result column="username" property="username"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>
    <select id="findOrderByRslMap" parameterType="int" resultMap="orderRslMap">
        SELECT
        o.*,u.username,u.address
        FROM
            orders o,user u
        WHERE
       	    o.user_id = u.id AND o.id=#{?};
</select>
//测试
@Test
public void test1(){
    SqlSession session = ssf.openSession();
    OrderMapper mapper = session.getMapper(OrderMapper.class);
    Orders orderByRslMap = mapper.findOrderByRslMap(5);
    System.out.println(orderByRslMap.toString());
    session.close();
}

注意:需要在Orders里添加User实例对象并提供get、set方法

private User user; //订单所属的用户

public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

总结

resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议使用resultType 。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用 resultMap可以完成将关联查询映射pojo的对象属性中。
resultMap可以实现延迟加载,resultType无法实现延迟加载。

一对多实现讲解

需求

首先根据用户 ID 读取一个用户信息,然后再读取这个用户所发布贴子(post)。

SELECT u.*,p.*
FROM user u,post p
WHERE u.id=p.userid AND id=1;

第一步:创建User类和Post类

//User.java
package model;

import java.io.Serializable;
import java.util.List;

public class User implements Serializable {
    private int id;
    private String username;
    private String mobile;
    private List<Post> posts;

    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 getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public List<Post> getPosts() {
        return posts;
    }

    public void setPosts(List<Post> posts) {
        this.posts = posts;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", mobile='" + mobile + '\'' +
                ", posts=" + posts +
                '}';
    }
}
//Post.java
package model;

public class Post {
    private int id;
    private User user;
    private String title;
    private String content;

    public int getId() {
        return id;
    }

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

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "Post{" +
                "id=" + id +
                ", user=" + user +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

第二步:创建User表的映射文件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">
<mapper namespace="mapper.UserMapper">
    <resultMap id="resultUserMap" type="user">
        <result property="id" column="user_id"/>
        <result property="username" column="username"/>
        <result property="mobile" column="mobile"/>
        <collection property="posts" ofType="model.Post" column="userid">
            <id property="id" column="post_id" javaType="int" jdbcType="INTEGER"/>
            <result property="title" column="title" javaType="string" jdbcType="VARCHAR"/>
            <result property="content" column="content" javaType="string" jdbcType="VARCHAR"/>
        </collection>
    </resultMap>
    <select id="getUserById" resultMap="resultUserMap" parameterType="int">
        SELECT u.*,p.*
        FROM user u,post p
        WHERE u.id=p.userid AND id=#{id};
    </select>
</mapper>

第三步:测试

@Test
public void test(){
    SqlSession session = ssf.openSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    User userById = mapper.getUserById(1);
    System.out.println(userById.toString());
    List<Post> posts = userById.getPosts();
    for (Post post : posts) {
        System.out.println(post.getTitle()+post.getContent());
    }
    session.close();
}

查询缓存

MyBatis的缓存理解

  • MyBatis的缓存,包括一级缓存和二级缓存,一级缓存是默认使用的。二级缓存需要手动开启。
  • 一级缓存指的就是sqlsession,在sqlsession中有一个数据区域,是map结构,这个区域就是一级缓存区域。一级缓存区域中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。
  • 二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构、这个区域就是一级缓存区域。

一级缓存

原理

测试1

测试2

二级缓存

原理

使用

开启二级缓存总开关

UserMapper中配置二级缓存

测试

禁用指定方法二级缓存

刷新缓存

整合ehcache

  • MyBatis本身是一个持久层框架,它不是专门的缓存框架,所以它对缓存的实现不够好,不能支持分布式。

  • Ehcache是一个分布式的缓存框架。

  • 什么是分布式

  • 系统为了提高性能,通常会对系统采用分布式部署(集群部署方式)

  • 整合思路

    • Cache是一个接口,它的默认实现是MyBatis的PerpetualCache。如果想整合mybatis的二级缓存,那么实现Cache接口即可。

    • 添加jar包

      ehcache-core-2.6.5.jar
      mybatis-ehcache-1.0.2.jar
      
    • 设置映射文件中cache标签的type值为ehcache的实现类

      <!--默认使用perpetualCache-->
      <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
      
    • 在src下添加ehcache.xml的配置文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
          <diskStore path="java.io.tmpdir"/>
          <defaultCache maxElementsInMemory="10000" eternal="false"
                        timeToIdleSeconds="120" timeToLiveSeconds="120"
                        maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120"
                        memoryStoreEvictionPolicy="LRU">
              <persistence strategy="localTempSwap"/>
          </defaultCache>
      </ehcache>
      
    • 配置文件参数说明

      参数名称代表意义
      maxElementsInMemory设置基于内存的缓存中可存放的对象最大数目
      eternal设置对象是否为永久的,true 表示永不过期,此时将忽略
      timeToIdleSeconds设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache 会把它从缓存中清除。如果此值为 0,表示对象可以无限期地处于空闲状态。
      timeToLiveSeconds设置对象生存最长时间,超过这个时间,对象过期。如果此值为 0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值
      overflowToDisk设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
      diskPersistent当 jvm 结束时是否持久化对象 true false 默认是false
      diskExpiryThreadIntervalSeconds指定专门用于清除过期对象的监听线程的轮询时间
      memoryStoreEvictionPolicy当内存缓存达到最大,有新的element 加入的时候, 移除缓存中 element 的策略。 默认是 LRU有 (最近最少使用),可选的有 LFU (最不常使用)和 FIFO (先进先出)
    • 测试:用上面二级缓存例子即可。

    • 二级缓存 应用场景
      使用场景: 对于访问响应速度要求高,但是实时性不高的查询,可以采用二级缓存技术。
      注意:在使用二级缓存的时候,要设置一下刷新间隔(cache 标签中有一个 flashInterval 属性)来定时刷新二级缓存,这个刷新间隔根据具体需求来设置,比如设置 30 分钟、60 分钟等,单位为毫秒。
      局限性
      Mybatis 二级缓存对细粒度的数据,缓存实现不好。
      场景
      对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次查询都是最新的商品信息,此时如果使用二级缓存,就无法实现当一个商品发生变化只刷新该商品的缓存信息而不刷新其他商品缓存信息,因为二级缓存是 mapper 级别的,当一个商品的信息发送更新,所有的商品信息缓存数据都会清空。解决此类问题,需要在业务层根据需要对数据有针对性的缓存。
      比如可以对经常变化的 数据操作单独放到另一个 namespace 的mapper中

MyBatis整合Spring

  • SSH:struts2+spring+hibernate

  • SSM:SpringMVC+Spring+MyBatis

  • 步骤

    • 导入MyBatis包

      <!--导入MyBatis核心包-->
      mybatis-3.2.7.jar
      <!--导入MyBatis依赖包-->
      asm-3.3.1.jar
      cglib-2.2.2.jar
      commons-logging-1.1.1.jar
      javassist-3.17.1-GA.jar
      log4j-1.2.17.jar
      log4j-api-2.0-rc1.jar
      log4j-core-2.0-rc1.jar
      slf4j-api-1.7.5.jar
      slf4j-log4j12-1.7.5.jar
      
    • 导入mysql数据库驱动

      mysql-connector-java-5.1.7-bin.jar
      
    • 数据库dbcp连接池

      commons-dbcp-1.4.jar
      commons-pool-1.5.6.jar
      
    • 导入spring_mvc包

      spring-aop-3.2.0.RC2.jar
      spring-aspects-3.2.0.RC2.jar
      spring-beans-3.2.0.RC2.jar
      spring-context-3.2.0.RC2.jar
      spring-context-support-3.2.0.RC2.jar
      spring-core-3.2.0.RC2.jar
      spring-expression-3.2.0.RC2.jar
      spring-jdbc-3.2.0.RC2.jar
      spring-test-3.2.0.RC2.jar
      spring-tx-3.2.0.RC2.jar
      spring-web-3.2.0.RC2.jar
      spring-webmvc-3.2.0.RC2.jar
      
    • MyBatis-Spring整合包

      mybatis-spring-1.2.2.jar
      
    • 配置MyBatis的核心配置文件

      核心配置文件、创建User模型、映射文件

      <?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>
              <package name="backoffice.model"/>
          </typeAliases>
          <mappers>
              <mapper resource="backoffice/sqlmap/User.xml"/>
          </mappers>
      </configuration>
      
      <?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="user">
          <select id="findUserById" parameterType="int" resultType="user">
              SELECT * FROM user WHERE id=#{id};
          </select>
      </mapper>
      
    • spring配置数据源、SqlSessionFactory、DaoBean

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/aop
             http://www.springframework.org/schema/aop/spring-aop.xsd">
          <!--配置数据库,dbcp数据库连接池-->
          <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
              <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
              <property name="url" value="jdbc:mysql://localhost:3306/spring_day3"/>
              <property name="username" value="root"/>
              <property name="password" value="123456"/>
              <!--最大连接-->
              <property name="maxActive" value="10"/>
              <!--最大空闲数-->
              <property name="maxIdle" value="5"/>
          </bean>
          <!--配置会话工厂-->
          <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
              <property name="configLocation" value="SqlMapConfig.xml"/>
              <property name="dataSource" ref="dataSource"/>
          </bean>
          <!--配置userDao-->
          <bean id="userDao" class="backoffice.dao.UserDaoImpl">
              <property name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
          </bean>
      </beans>
      
    • 编写UserDao接口及接口实现类UserDaoImpl

      //UserDao.java
      package backoffice.dao;
      
      import backoffice.model.User;
      
      public interface UserDao {
          public User findUserById(Integer id);
      }
      //UserDaoImpl.java
      package backoffice.dao;
      
      import backoffice.model.User;
      import org.mybatis.spring.support.SqlSessionDaoSupport;
      
      public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
          @Override
          public User findUserById(Integer id) {
              return this.getSqlSession().selectOne("user.findUserById",id);
          }
      }
      
    • 测试

      package backoffice.test;
      
      import backoffice.dao.UserDao;
      import backoffice.model.User;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class one {
          @Test
          public void test(){
              ApplicationContext context =
                      new ClassPathXmlApplicationContext("beans.xml");
              UserDao userDao = (UserDao)context.getBean("userDao");
              User user = userDao.findUserById(1);
              System.out.println(user);
          }
      }
      
  • Spring整合MyBatis,通过Mapper接口整合dao

    • 创建Mapper映射文件

      //UserMapper.java
      package backoffice.mapper;
      
      import backoffice.model.User;
      
      public interface UserMapper {
          public User findUserById(int id);
      }
      
    • 配置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">
      <mapper namespace="backoffice.mapper.UserMapper">
          <select id="findUserById" parameterType="int" resultType="user">
              SELECT * FROM user WHERE id = #{id};
          </select>
      </mapper>
      
    • 核心配置文件加载映射文件

      <mappers>
              <!--批量加载所有的mapper接口和mapper映射文件-->
              <package name="backoffice.mapper"/>
          </mappers>
      
    • Spring配置MapperFactoryBean

      //beans.xml
      <!--配置userDao-->
          <bean id="userDao" class="backoffice.dao.UserDaoImpl">
              <property name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
      </bean>
      
    • 测试

      package backoffice.test;
      
      import backoffice.dao.UserDao;
      import backoffice.mapper.UserMapper;
      import backoffice.model.User;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class one {
          @Test
          public void test(){
              ApplicationContext context =
                      new ClassPathXmlApplicationContext("beans.xml");
              UserMapper mapper = (UserMapper) context.getBean("userMapper");
              User user = mapper.findUserById(10);
              System.out.println(user);
          }
      }
      
      
    • 用MapperScannerConfigurer批量扫描创建代理对象

      <!--mapper代理开发方式之批量代理mapper配置,bean的名字
          默认为mapper接口类名的首字母小写
          注意:
          1、JDK1.8用这种方式不行,bean不能创建成功,改成jdk1.7即可
          2、或者spring换成spring3.2.9或以上就OK了
      -->
      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
          <property name="basePackage" value="backoffice.mapper"/>
      </bean>
      

逆向工程

简介

简单点说,就是通过数据库中的单表,自动生成Java代码

Mybatis 官方提供了逆向工程
可以针对单表自动生成 mybatis 代码(mapper.java\mapper.xml\po
类)
企业开发中,逆向工程是个很常用的工具。

下载逆向工程

https://github.com/mybatis/generator/releases

使用方法

  • 创建简单的Java项目
  • 导入jar包,创建generator配置文件
  • 使用Java类来执行逆向工程
  • 把生成的代码拷贝到项目中
  • 在正式项目中使用逆向工程生成的代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值