mybatis进击

MyBatis深入

一、Dao的开发

1. 原始Dao

程序员写好Dao接口和Dao实现类

例子:

    1. Dao interface
package dao;

import pojo.User;

import java.util.List;

public interface UserDao {

    public User findUserById(Integer id);

    public List<User> findUserByUserName(String userName);
}
    1. DaoImpl
package dao;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import pojo.User;

import java.util.List;

public class UserDaoImpl implements UserDao {
    private SqlSessionFactory sqlSessionFactory;

    // 通过构造方法注入
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }
    public User findUserById(Integer id) {
        // SQLSession是线程不安全的,所以最佳使用方法是放在方法体内
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("test.findUserById", id);
        return user;
    }
    public List<User> findUserByUserName(String userName) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> user = sqlSession.selectList("test.findUserByUserName", userName);
        return user;
    }
}
    1. Test Dao
package dao;

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 pojo.User;

import java.io.IOException;
import java.io.InputStream;

import static org.junit.Assert.*;

public class UserDaoImplTest {
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void Init() throws IOException {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }
    public void testFindUserById(){
        UserDao userDao= new UserDaoImpl(sqlSessionFactory);
        User user = userDao.findUserById(1);
        System.out.println(user);
    }
}

原始Dao开发中存在以下问题:

Dao方法体存在重复代码:

通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法

不利于维护:

调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码

2. Mapper动态代理

由程序员编写Mapper接口(类似Dao接口),由mybatis框架根据mapper接口自动创建动态代理对象,代理对象的方法类似Dao实现类的方法。

规范:

  1. Mapper.xml文件中的namespace和mapper接口的类路径相同;
  2. Mapper接口方法名和Mapper.xml中定义的每个statement的id相同;
  3. Mapper接口方法的输入参数类型和Mapper.xml文件中定义的每一个sql的parameterType的类型相同;
  4. Mapper接口方法的输出参数类型和Mapper.xml文件中定义的每一个sql的resultType的类型相同。

    1. 映射文件—–Mapper.xml

    Mapper.xml的编写方法和User.xml文件方法相同(User.xml文件参考链接http://blog.youkuaiyun.com/jun8148/article/details/79404553”>点我呀),

    文件放于maven工程的resources目录下,与Mapper.java的包路径一样哦,后面有文件的图解哦!!!

    <?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.Mapper">
       <!-- 根据id获取用户信息 -->
       <select id="findUserById" parameterType="int" resultType="pojo.User">
           select * from user where id = #{id}
       </select>
       <!-- 自定义条件查询用户列表 -->
       <select id="findUserByUsername" parameterType="java.lang.String" resultType="pojo.User">
           SELECT * FROM user WHERE username LIKE '%${value}%'
       </select>
       <!-- 添加用户 -->
       <insert id="insertUser" parameterType="pojo.User">
           <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
               SELECT LAST_INSERT_ID()
           </selectKey>
           INSERT INTO user(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
       </insert>
    
    </mapper>
    
    1. Mapper.java(interface)

    注意事项:

    1. Mapper接口的方法名和Mappper.xml中定义的statement的id相同
    2. Mapper接口的方法的输入参数和Mapper.xml中定义的statement的parameterType类型相同
    3. Mapper接口的方法的输出参数和Mapper.xml中定义的statement的resultType类型相同
    package mapper;
    
    import pojo.User;
    
    import java.util.List;
    
    public interface Mapper {
       /**
        * 根据用户id查询用户信息
        * @param id id
        * @return User
        * @throws Exception
        */
       public User findUserById(int id) throws Exception;
    
       /**
        * 查询用户列表
        * @param username username
        * @return List<User>
        * @throws Exception
        */
       public List<User> findUserByUsername(String username) throws Exception;
    
       /**
        * 添加用户信息
        * @param user  user
        * @throws Exception
        */
       public void insertUser(User user)throws Exception;
    }
    
    1. 加载Mapper.xml

    在SqlMapConfig.xml文件中添加

    <mappers>
    <mapper resource="mapper/Mapper.xml"/>
    </mappers>
    1. 测试
    package mapper;
    
    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 pojo.User;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Date;
    import java.util.List;
    
    import static org.junit.Assert.*;
    
    public class MapperTest {
       private SqlSessionFactory sqlSessionFactory;
       @Before
       public void init() throws IOException {
           String resouce = "SQLMapConfig.xml";
           InputStream inputStream = Resources.getResourceAsStream(resouce);
           sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
       }
       @Test
       public void findUserById() throws Exception {
           // 获取session
           SqlSession session = sqlSessionFactory.openSession();
           // 获取mapper接口的代理对象
           Mapper userMapper = session.getMapper(Mapper.class);
           // 调用代理对象方法
           User user = userMapper.findUserById(1);
           System.out.println(user);
           // 关闭session
           session.close();
       }
    
       @Test
       public void findUserByUsername() throws Exception {
           SqlSession sqlSession = sqlSessionFactory.openSession();
           Mapper userMapper = sqlSession.getMapper(Mapper.class);
           List<User> list = userMapper.findUserByUsername("张");
           System.out.println(list.size());
    
       }
    
       @Test
       public void insertUser() throws Exception {
           SqlSession session = sqlSessionFactory.openSession();
           Mapper userMapper = session.getMapper(Mapper.class);
           // 要添加的数据
           User user = new User();
           user.setUsername("fuck");
           user.setBirthday(new Date());
           user.setSex("1");
           user.setAddress("New  York");
           userMapper.insertUser(user);
           // 提交事物
           session.commit();
           session.close();
       }
    }

二、SqlMapConfig.xml文件

  1. ### 映射器<mappers>
<mapper resource=""/>
相对于类路径的资源
eg:<mapper resource="test/User.xml"/>


<mapper class=""/>
mapper接口类路径
这种要求mapper接口名称和mapper.xml文件名相同,且在同一目录内
eg:<mapper class="test1.test2.Mapper"/>

<package name=""/>
扫描并注册指定包下的所有mapper接口
这种要求mapper接口名称和mapper.xml文件名相同,且在同一目录内
eg:<package name="test.mapper"/>
扫描test.mapper包下的Mappper接口

三、附目录图

这里写图片描述

四、动态Sql

关键字:if、where、foreach、include

以代码为例哈

<!--比如我们要查询一个用户,既可以根据id查询,也可以根据名字查询,或者可以根据两者综合查询-->
    <select id="findUser" parameterType="pojo.user" resultType="pojo.user">
        SELECT * FROM user
        <where>
            <if test="id=null and id!=''">
                and id=#{id}
            </if>
            <if test="username != null and username!=''">
                and username LIKE '%${username}%'
            </if>
        </where>
    </select>
<!--    
if标签就是跟java的if选择结构一样的,test的内容就是条件,如果满足就执行,不满足就不执行
where标签就是自动为sql添加上where关键字,并且能自动去掉第一个and
-->

<!--根据多个id查询用户-->
    <select id="findUserByIds" parameterType="vo.Test" resultType="pojo.User">
        SELECT * FROM user
        <if test="Ids!=null and Ids.size>0">
            <foreach collection="Ids" open="where id in(" close=")" item="id" separator=", ">
                #{id}
            </foreach>
        </if>
    </select>
<!--    
foreach功能就是依次遍历collection内的集合 open就是自动添加到之前的sql片段 close是结尾的 item是遍历到的每个对象存放的变量,separator是分隔符
比如我们跟据1,3,5,7,9查询上面的完整sql语句就是
select * from user where id in(1, 3, 5, 7, 9)
-->


       <sql id="tests">
        <if test="id!=null and id!=''">
            and id=#{}
        </if>
        <if test="username!=null and username!=''">
            and usernam='%${username}%'
        </if>
    </sql>
    <select id="findUser" parameterType="pojo.User" resultType="pojo.User">
        SELECT * FROM user
        <where>
            <include refid="tests"></include>
        </where>
    </select>


<!--    
如果我们有重复的sql片段我们可以将其提出到<sql></sql>标签中 id是sql片段的唯一标识
当我们需要使用到这个片段的时候我们就可以利用<include></include>标签来引用它 refid就是sql片段的id
如果我们需要引用其他的namespace中的sql片段 就必须加上namespace名称
<include refid="namespace.sql"></include>
-->
    <sql id="tests">
        <if test="id!=null and id!=''">
            and id=#{}
        </if>
        <if test="username!=null and username!=''">
            and usernam='%${username}%'
        </if>
    </sql>
    <select id="findUser" parameterType="pojo.User" resultType="pojo.User">
        SELECT * FROM user
        <where>
            <include refid="tests"></include>
        </where>
    </select>

五、关联查询

假设在我们的user表的基础上添加一个cart表,里面有用户的购物信息

table of user:
id username sex address

table of cart:
id userId number note

class of User :
id(int) username(String) sex(String) address(String)

class of Cart:
id(int) userId(int) number(String) details(String)
  1. 一对一

    1. 方法一(用的是Mapper哦)

      定义专门的一个类来作为输出类型

      创建一个CartManager类继承Cart,然后把用户类的信息定义到该类中

      // 位于pojo包内
      public CartManager extends Cart{
      private String  username;
      private String address;
      // get set methods
      没有检查过代码 随便敲的 有错自己改一下哦 
      }

      查询(Mapper.xml)

      <!--查询cart中的userId和user中的id相等的信息-->
      <select id="findCartList" resultType="pojo.CartManager">
      SELECT cart.*, user.username, user.address FORM cart,user WHERE cart.userId = user.id
      </select>

      Mapper.java(接口)

      public List<CartManager> findCartList() throws Exception;

      测试自己写咯

      List<CartManager> list = sqlSession.getMapper(Mapper.class)

    2. 方法二

      使用resultMap

      Cart类有所改变,需要将User加入到Cart中

      class of Cart:
      id(int) userId(int) number(String) details(String) user(User)

      Mapper.xml

        <resultMap id="findCartListResultMap" type="pojo.Cart">
      
            <!-- column:表的对应的列  property:user对象中id属性-->
            <id column="id" property="id"/>
            <result column="id" property="userId"/>
            <result column="number" property="number"/>
            <result column="details" property="details"/>
      
            <!--property是Cart对象中的user属性,javaType是user属性对应的类型-->
            <association property="user" javaType="pojo.User">
                <id column="user_id" property="id"/>
                <result column="username" property="username"/>
                <result column="address" property="address"/>
      
            </association>
      
        </resultMap>
      
        <select id="findCartList" resultMap="findCartListResultMap">
            SELECT cart.*, user.username,user.address FROM WHERE cart.userId = user.id
        </select>

  2. 一对多

    一个用户对应多个cart

    更改User类

    class of User
    id(int) username(String) sex(String) address(String) carts(List<Cart>)

    Mapper.xml

       <resultMap type="pojo.user" id="userCartManagerResultMap">
           <!-- 用户信息映射 -->
           <id property="id" column="id"/>
           <result property="username" column="username"/>
           <result property="sex" column="sex"/>
           <result property="address" column="address"/>
           <!-- 一对多关联映射 -->
           <collection property="carts" ofType="pojo.Cart">
               <id property="id" column="cid"/>
               <!--用户id已经在user对象中存在,此处可以不设置-->
               <!-- <result property="userId" column="id"/> -->
               <result property="number" column="number"/>
               <result property="details" column="details"/>
           </collection>
    <!--
    collection部分定义了用户关联的信息。表示关联查询结果集
    property="carts":关联查询的结果集存储在User对象的上哪个属性(carts)。
    ofType="pojo.Cart":指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。
    <id />及<result/>的意义同一对一查询。
    -->
       </resultMap>
       <select id="userCartManager" resultMap="userCartManagerResultMap">
           SELECT
           user.*, cart.id cid,
           cart.number,
           cart.createtime,
           cart.note
           FROM
           `user` u
           LEFT JOIN cart c ON u.id = c.userId
       </select>
    

    Mapper接口

    public List<User> userCartManager();

    测试

    Mapper mapper = session.getMapper(Mapper.class);
    List<User> users = mapper.userCartManager();
    session.close();

六、MyBatis整合Spring

附一张目录图这里写图片描述

  1. 利用maven创建一个工程

这里写图片描述

可以选择创建webapp或者quickstart

  1. 在pom.xml文件中添加依赖

       <!--Spring依赖-->
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-core</artifactId>
         <version>4.3.2.RELEASE</version>
       </dependency>
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context</artifactId>
         <version>4.3.2.RELEASE</version>
       </dependency>
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-test</artifactId>
         <version>4.3.2.RELEASE</version>
       </dependency>
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-tx</artifactId>
         <version>4.3.2.RELEASE</version>
       </dependency>
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-beans</artifactId>
         <version>4.3.2.RELEASE</version>
       </dependency>
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-jdbc</artifactId>
         <version>4.3.2.RELEASE</version>
       </dependency>
    
       <!--mybatis依赖-->
       <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.3.0</version>
       </dependency>
       <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis-spring</artifactId>
         <version>1.3.0</version>
       </dependency>
       <!-- mysql驱动包 -->
       <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>5.1.35</version>
       </dependency>
     <!--阿里的druid数据源jar包依赖-->
       <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>druid</artifactId>
         <version>1.0.18</version>
       </dependency>
       <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
       </dependency>
  2. 编写jdbcConfig.properties文件

    
    #jdbcConfig.properties
    
    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/testSpring
    jdbc.username=root
    jdbc.password=1234
    用来检测连接是否有效的sql,要求是一个查询语句。
    
    如果validationQuery为null,testOnBorrow、testOnReturn、
    
    testWhileIdle都不会起作用。
    
      validationQuery=SELECT 1
    
    初始化连接大小
    
      jdbc.initialSIze=0
    
    连接池最大使用连接数量
    
      jdbc.maxActive=20
    
    连接池最小空闲
    
      jdbc.minIdle=0
    
    获取连接最大等待时间
    
      jdbc.maxWait=60000
  3. 编写spring-mybatis.xml文件

    <?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:tx="http://www.springframework.org/schema/tx"
          xmlns:aop="http://www.springframework.org/schema/aop"
          xmlns:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
       <!--********************************************************************************************-->
       <!--设置扫描的包-->
       <context:component-scan base-package="com.lj.service"></context:component-scan>
       <!--********************************************************************************************-->
    
       <context:property-placeholder location="classpath:jdbcConfig.properties" ignore-unresolvable="true"/>
    
       <!-- 配置数据源 -->
       <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
             init-method="init" destroy-method="close">
           <property name="url" value="${jdbc.url}"/>
           <!--
           不必显示配置DriverClass Druid根据url前缀自动设别DriverClass
           <property name="driverClassName" value="${jdbc.driverClassName}"/>
           -->
           <property name="username" value="${jdbc.username}"/>
           <property name="password" value="${jdbc.password}"/>
           <!-- 初始化连接大小 -->
           <property name="initialSize" value="${jdbc.initialSIze}"/>
           <!-- 连接池最大使用连接数量 -->
           <property name="maxActive" value="${jdbc.maxActive}"/>
           <!-- 连接池最小空闲 -->
           <property name="minIdle" value="${jdbc.minIdle}"/>
           <!-- 获取连接最大等待时间 -->
           <property name="maxWait" value="${jdbc.maxWait}"/>
           <!--   用来检测连接是否有效的sql,要求是一个查询语句。
              如果validationQuery为null,testOnBorrow、testOnReturn、
              testWhileIdle都不会起作用。-->
           <property name="validationQuery" value="${validationQuery}"/>
           <!--申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。缺省值为true-->
           <property name="testOnBorrow" value="false"/>
           <!--归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。缺省值为false-->
           <property name="testOnReturn" value="false"/>
           <!--
           建议配置为true,不影响性能,并且保证安全性。
           申请连接的时候检测,如果空闲时间大于
           timeBetweenEvictionRunsMillis,
           执行validationQuery检测连接是否有效。缺省值为false
           -->
           <property name="testWhileIdle" value="true"/>
           <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接-->
          <property name="timeBetweenEvictionRunsMillis" value="60000"/>
          <!-- 配置一个连接在池中最小生存的时间 -->
          <property name="minEvictableIdleTimeMillis" value="25200000"/>
          <!-- 打开removeAbandoned功能 -->
          <property name="removeAbandoned" value="true"/>
          <property name="removeAbandonedTimeout" value="1800"/>
          <!-- 关闭abanded连接时输出错误日志 -->
          <property name="logAbandoned" value="true"/>
          <!--
          监控数据库
          属性类型是字符串,通过别名的方式配置扩展插件,
          常用的插件有:
          监控统计用的filter:stat
          日志用的filter:log4j
          防御sql注入的filter:wall
          -->
          <property name="filters" value="stat"/>
      </bean>       
       <!-- myBatis文件 -->
       <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
           <property name="dataSource" ref="dataSource"/>
    
           <!--********************************************************************************************-->
           <!-- 配置数据库表对应的java实体类 -->
           <property name="typeAliasesPackage" value="com.lj.pojo"/>
           <!--********************************************************************************************-->
           <!--********************************************************************************************-->
           <!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
    
           <property name="mapperLocations" value="com/lj/mapper/*.xml"/>
           <!--********************************************************************************************-->
       </bean>
       <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
           <!--********************************************************************************************-->
           <property name="basePackage" value="com.lj.mapper"/>
           <!--********************************************************************************************-->
           <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
       </bean>
    </beans>

    此处代码大都是copy的,不需要去记,知道怎么用就行了。 含有 的地方就是你需要更改成自己的东西的地方

  4. 编写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="com.lj.mapper.UserMapper">
    <select id="findUserById" parameterType="java.lang.Integer" resultType="User">
       SELECT * FROM user WHERE id=#{id}
    </select>
    </mapper>
    
  5. UserMapper接口

    package com.lj.mapper;
    
    import com.lj.pojo.User;
    
    public interface UserMapper {
       public User findUserById(int id);
    
    }
    
  6. User.java

    package com.lj.pojo;
    
    public class User {
       private int id;
       private String userName;
       private String password;
       // 自己补充完整 记得有无参构造方法哦
    }
  7. UserService

    package com.lj.service;
    
    import com.lj.pojo.User;
    
    public interface UserService {
    
       User getUserById(int id);
    }
    
  8. UserServiceImpl

    package com.lj.service.impl;
    
    import com.lj.mapper.UserMapper;
    import com.lj.pojo.User;
    import com.lj.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service("userService")
    public class UserServiceImpl implements UserService {
       @Autowired
       private UserMapper userMapper;
       public User getUserById(int id) {
           User user = userMapper.findUserById(id);
           return user;
       }
    }
  9. test

    import com.lj.service.UserService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import static org.junit.Assert.*;
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
    public class UserTest {
      @Autowired
      private UserService userService;
      @Test
      public void testFindUserById(){
          User user = userService.getUserById(1);
          System.out.println(user);
      }
    }

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值