mybatis框架--初级

2017.2.18-2017.2.23

上次跟书里学的mybatis,好像我学了个假的mybatis,现在跟一个视屏学

第一个例子

  1. 导入jar包,将mybatis文件夹下的所有jar包导入,还有数据库的
  2. 创建mybatis的配置文件,名称位置任意,如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 resource="db.properties"/>  <!-- 加上配置路径 -->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC" />
                <dataSource type="POOLED">          
                    <property name="url" value="${url}" />
                    <property name="driver" value="${drivername}" />
                    <property name="username" value="${username}" />
                    <property name="password" value="${password}" />
                </dataSource>
            </environment>
        </environments>
        <!-- 加载映射文件 -->
        <mappers>
            <mapper resource="sqlmap/mapper.xml"/>
        </mappers>
    
    </configuration>
    
  3. 将数据库的配置写入db.properties中

    url=jdbc:mysql:///mybatis
    drivername=com.mysql.jdbc.Driver
    username=root
    password=root
    
  4. 创建pojo类,如User

  5. 创建映射文件,如:mapper.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" >
    <!-- namespace命名空间,作用就是对SQL进行分类化管理 -->
    <mapper namespace="zcw">
        <!-- 在映射文件中配置很多SQL语句 -->
        <!-- 通过select执行数据库查询
             id:标识映射文件中的sql
             将SQL语句封装到Statement对象中,所以将id称为statement的id、
             #{}标识一个占位符 
         -->
        <select id="findUserById" parameterType="int" resultType="cn.zcw.po.User">
            select * from user where id=#{id}
        </select>
    </mapper> 
    
  6. 写测试类进行测试,如通过id查询

    @Test
    public void findByIdTest() throws IOException{
        //mybatis配置文件
        String resource="SqlMapConfig.xml";
        //配置文件流
        InputStream inputStream=Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
        //通过工厂得到SqlSession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //通过SqlSession操作数据库
        //第一个参数:映射文件中的namespace+statement的id
        //第二个参数:指定和映射文件中匹配的parameterType类型
        User user=sqlSession.selectOne("zcw.findUserById", 6);
        System.out.println(user);
    }
    

根据字段模糊查询数据

  1. 在mybatis的映射文件中配置SQL语句

    <!-- 根据name模糊查询user -->
    <!-- ${}表示拼接sql串,将接收到的参数内容不加修饰的拼接在sql中
         但是这样可能会引起sql注入
         ${value}:接收参数的内容,如果传入类型是简单类型,${}中只能使用value
     -->
    <select id="findUserByName" parameterType="String" resultType="cn.zcw.po.User">
        select * from user where username like '%${value}%'
    </select>
    
  2. 单元测试(核心代码)

    List<User> users=sqlSession.selectList("zcw.findUserByName", "z");
    

#{}和${}

  1. #{},表示一个占位符

    #{}接收输入参数,类型可以是简单类型、pojo、hashmap。

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

    #{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值。

  2. ${},表示字符串连接,会引起sql注入,不建议使用

    ${}接受参数,类型可以是简单类型、pojo、hashmap

    如果接收简单类型,${}中只能写成value

    ${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值。

插入操作

  1. 在映射文件中配置添加用户的statement

    <!-- 添加用户
         parameterType:指定输入参数类型是pojo
         ${}中指定pojo的属性名
     -->
    <insert id="insertUser" parameterType="cn.zcw.po.User">
        insert into user(id,username,password) values(#{id},#{username},#{password})
    </insert>
    
  2. 单元测试(注意:最后要提交)

    User user=new User();
    user.setUsername("张三");
    user.setPassword("password");
    sqlSession.insert("zcw.insertUser",user);
    //提交事务
    sqlSession.commit();
    

获得刚插入的id

  1. 主键自动生成

    1. 配置映射文件

      <insert id="insertUser" parameterType="cn.zcw.po.User">
          <!-- 
              将插入数据的主键返回,返回到user对象中
              select last_insert_id():得到刚insert进去记录的主键值,只使用与自增主键
              keyProperty:将查询到主键值设置到parameterType指定的对象的那个属性
              order:selecr last_insert_id():执行顺序,相对于insert语句
              resultType:select last_insert_id()返回的类型
           -->
          <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
              select last_insert_id()
          </selectKey>
      
          insert into user(id,username,password) values(#{id},#{username},#{password})
      </insert>
      
    2. 单元测试

      User user=new User();
      user.setUsername("张三");
      user.setPassword("password");
      sqlSession.insert("zcw.insertUser",user);
      System.out.println(user.getId());
      //提交事务
      sqlSession.commit();
      
  2. uuid主键

    1. 配置映射文件

      <!-- 使用mysql的uuid()生成主键
           执行过程:
           首先通过uuid()得到主键,将主键设置到user对象的id属性中
           其次在insert执行时,从user对象中取出id属性值
       -->
       <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
          select uuid()
       </selectKey>
      

删除操作

  1. 在映射文件中配置删除的statement

    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id=#{id}
    </delete>
    
  2. 测试代码(注意:要commit)

更新操作

  1. 在映射文件中配置更新的statement

    <!-- 更新操作 -->
    <update id="updateUser" parameterType="cn.zcw.po.User">
        update user set username=#{username},password=#{password} where id=#{id}
    </update>
    
  2. 测试代码(注意:要commit)

    User user=new User();
    user.setId(1);
    user.setPassword("password");
    user.setUsername("张常文");
    sqlSession.update("zcw.updateUser",user);
    sqlSession.commit();
    

hibernate和mybatis的应用场景

  1. hibernate:是一个标准ORM框架。入门门槛较高,不需要写SQL语句。但是对SQL语句进行优化、修改比较困哪。应用场景:适用于需求变化不多的中小型项目,比如:后台管理系统,erp,orm,oa

  2. mybatis:专注SQL本身,需要程序员自己编写sql语句,SQL修改、优化比较方便。mybatis是一个不完全的ORM框架。虽然程序员自己写SQL,mybatis也可以实现映射(输入映射、输出映射)。应用场景:使用与需求变化较多的项目,比如:互联网项目。

SqlSession、SqlSessionFactory、SqlSessionFactoryBuilder

  1. SqlSession是一个面向用户的接口,他是线程不安全的,SqlSession最佳应用场合是在方法体内,定义成局部变量使用

  2. SqlSessionFactory只需创建一次,所以使用单例模式

  3. SqlSessionFactoryBuilder用工具类获取

原始dao的应用

  1. 创建UserDao接口

    public interface UserDao {
        public User findUserById(Integer id);
        public void insertUser(User user);
        public void deleteUser(Integer id);
    }
    
  2. 创建类UserDaoImpl类实现UserDao接口,并注入SqlSessionFactory对象
    public class UserDaoImpl implements UserDao{
    private SqlSessionFactory sqlSessionFactory=null;

        public  UserDaoImpl(SqlSessionFactory sqlSessionFactory){
            this.sqlSessionFactory=sqlSessionFactory;
        }
    
        @Override
        public User findUserById(Integer id) {
            //需要将SqlSession放到方法体内,因为其不是线程安全类
            SqlSession sqlSession=sqlSessionFactory.openSession();
            User user=sqlSession.selectOne("zcw.findUserById",id);
            return user;
        }
    
        @Override
        public void insertUser(User user) {
            SqlSession sqlSession=sqlSessionFactory.openSession();
            sqlSession.insert("zcw.insertUser",user);
            sqlSession.commit();        
        }
    
        @Override
        public void deleteUser(Integer id) {
            // TODO Auto-generated method stub
            SqlSession sqlSession=sqlSessionFactory.openSession();
            sqlSession.delete("zcw.deleteUser",id);
        }
    
    }
    
  3. 创建测试类测试,向UserDao中注入SqlSessionFactory对象

    public class test {
        private SqlSessionFactory sqlSessionFactory;
        //@Before会在@Test之前执行
        @Before
        public void init() throws IOException{
            String resource="SqlMapConfig.xml";
            InputStream inputStream=Resources.getResourceAsStream(resource);
            sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
        }
        @Test
        public void test(){
            UserDao userDao=new UserDaoImpl(sqlSessionFactory);
            User user=userDao.findUserById(2);
            System.out.println(user);
    
        }
    }
    

mapper.xml开发规范

  1. 在mapper.xml中的namespace等于mapper.java接口的全路径
  2. mapper.java接口中的方法输入参数类型和mapper.xml中statement的id一致
  3. mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致
  4. mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致

selectOne和selectList

  1. selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现,使用selectList也可以实现
  2. selectList表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne。如果使用selectOne会报错

mapper接口方法参数只能有一个是否影像系统开发

即使mapper接口只有一个参数,可以适用包装类型的pojo满足不同的业务方法的需求

SqlMapConfig.xml

  1. properties属性,可以将数据库的配置写到db.properties文件中,通过此属性读取
  2. typeAliases(别名)

    在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输入结果的映射类型。要定义在environments标签之前。

    <!-- 定义别名 -->
    <typeAliases>
        <!-- 定义单个别名
             type:类的全路径
             alias:别名
         -->
        <!-- <typeAlias type="cn.zcw.po.User" alias="user"/> -->
        <!-- 批量定义别名
             别名就是类名
         -->
         <package name="cn.zcw.po"/>
    </typeAliases>
    
  3. mappers

    1. resource

      <mapper resource="sqlmap/mapper.xml"/>
      
    2. class

      <!-- 通过mapper接口加载单个映射文件
           规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在同一目录下
           前提:使用mapper代理的方法
       -->
      <mapper class="cn.zcw.mapper.UserMapper"/>
      
    3. 批量加载

      <!-- 批量加载
           规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在同一目录下
           前提:使用mapper代理的方法
       -->
      <package name="cn.zcw.mapper"/>
      

输入映射–pojo包装类型实现

  1. 创建UserCustom.java类继承User(扩展User)
  2. 创建USerVo.java类包含UserCustom对象属性,并生成其get、set方法
  3. 在映射文件中配置statement

     <select id="findUser" parameterType="cn.zcw.po.UserVo" resultType="cn.zcw.po.UserCustom">
        select * from user where username=#{userCustom.username}        
     </select>
    
  4. 在mapper接口类中声明对应的findUser方法
  5. 测试

    //调用userMapper对象的方法
    UserVo userVo=new UserVo();
    UserCustom userCustom=new UserCustom();
    userCustom.setUsername("张常文");
    userVo.setUserCustom(userCustom);
    
    UserCustom user=userMapper.findUser(userVo);
    System.out.println(user);
    

resultType

使用resultType进行输出映射,只有查询出来的列明和pojo中的属性名一致,该列才可以映射成功

resultMap

 <!-- 定义resultMap
           将select id id_,username username_,password password_ from user 和User类中的属性做一个映射关系

      type:resultMap最终映射的Java对象类型,可以使用别名
      id:对resultMap的唯一标识
  -->
 <resultMap type="User" id="userResultMap">
    <!-- id表示查询结果集中的唯一标识
          colume:查出来的列名
          property:type指定的pojo类型中的属性名
     -->
    <id column="id_" property="id"/>
    <!-- result:对普通名称映射定义
          column:查询出来的列名
          property:type指定pojo类型中的属性名
     -->
     <result column="username_" property="username"/>
     <result column="password_" property="password"/>
 </resultMap>

 <!-- resultMap为resultMap的id -->
 <select id="findUserMap" parameterType="cn.zcw.po.UserVo" resultMap="userResultMap">
     select id id_,username username_,password password_ from user 
 </select>

动态sql

mybatis核心对SQL语句灵活操作,通过表达式进行判断,对SQL进行灵活拼接

sql片段

    <sql id="userinfoField">id,name,password</sql>
    <select id="getUserinfoAll" resultType="map">
        select 
        <include refid="userinfoField"/>
        form 
        userinfo
    </select>

一对一查询–resultType

描述:一个订单只属于一个用户,一对一关系。订单表中有一个外键对应用户表中的id

例子:查询订单的基本信息和对应的用户信息

  1. 创建user表对应的User实体类,创建UserCustom类继承User类并且创建Order表对应的属性
  2. 实现映射关系表。返回类型为UserCustom

    <select id="selectUserOrder" resultType="UserCustom">
        select `user`.*,number from user,orders WHERE `user`.id=orders.user_id
    </select>
    
  3. 在mapper接口中实现相应的方法

一对一查询–resultMap

描述、例子与上述相同

  1. 创建Order实体类,在Order类中声明User对象
  2. 创建resultMap

    <resultMap type="cn.zcw.mapper.Order" id="userOrder">
        <!-- 配置映射的订单信息 
             id:查询列中的唯一标识,这里就是orders的id列
        -->
        <id column="id" property="id"/>
        <result column="number" property="number"/>
    
        <!-- 配置映射的关联用户信息
             peoperty:映射到order类中的哪个属性
         -->
        <association property="user" javaType="cn.zcw.mapper.User">
            <!-- id:关联用户的唯一标识 -->
            <id column="user_id" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
        </association>
    </resultMap>
    
  3. 创建statement,resultMap等于userOrder

一对多查询

例子:查询订单-订单明细,一对多的查询,顺带查询出对应用户

  1. 创建Items实体类
  2. 创建Orders类,属性对应order表,user属性,List属性
  3. 构件resultMap(因为其也需查询出user和order的信息,所以可以继承上面的userOrder)

    <!-- 配置订单查询订单明细及用户信息的一对多resultMap -->
    <resultMap type="cn.zcw.mapper.Orders" id="userOrderItems" extends="userOrder">
        <collection property="items" ofType="cn.zcw.mapper.Items">
            <!-- id:items的唯一标识 -->
            <id column="items_id" property="id"/>
            <result column="itemname" property="itemname"/>
            <result column="orders_id" property="orders_id"/>
        </collection>
    </resultMap> 
    

多对多查询

例子:查询用户对商品,商品对明细是一对多,所以用户对商品为多对多关系。

  1. 在user实体类中声明List属性,在Order实体类中声明List属性,在OrderDetail中声明Items属性
  2. 配置resultMap

    <resultMap type="cn.zcw.mapper.User" id="userItems">
    
        <id column="id" property="id"/>
        <result></result>
    
        <!-- 一个用户对应多个订单 -->
        <collection property="orderList" ofType="cn.zcw.mapper.Order">
            <id column="order_id" property="id"/>
    
            <!-- 一个订单对应多个订单明细 -->
            <collection property="orderDetailList" ofType="cn.zcw.mapper.OrderDetail">
                <id column="orderDetail_id" property="id"/>
    
                <!-- 一个订单明细对应一个商品 -->
                        <association property="items" javaType="cn.zcw.mapper.Items">                       
                            <id column="items_id" property="id"/>
                        </association>
            </collection>
        </collection>
    
    </resultMap>
    

延迟查询

select order.*,user.* from order,user where order.userid=user.id作为延迟查询先select * from order单表查询,当Order对象获得user时再来发送SQL查询相应的user对象

  1. 创建order类,包含user对象属性
  2. 创建statement,单表查询

    <select id="findUserOrderLazyLoding" resultMap="UserOrderLazyLodingResultMap">
        select * from orders
    </select>
    
  3. 创建resultMap

    <!-- 延迟加载的resultMap -->
    <resultMap type="cn.zcw.mapper.Order" id="UserOrderLazyLodingResultMap">
        <!-- 配置映射的订单信息 -->
        <id column="id" property="id"/>
        <result column="number" property="number"/>
        <result column="user_id" property="user_id"/>
    
        <!--  select值为完成order.userid=user.id的statement的id,column为查询条件 -->
        <association property="user" javaType="cn.zcw.mapper.User" select="findUserById" column="user_id">
        </association>
    </resultMap>
    
    <select id="findUserById" parameterType="java.lang.Integer"     resultType="cn.zcw.mapper.User">
        select * from user where id=#{value}
    </select>
    
  4. 在SqlMapConfig.xml中配置延迟加载

    <settings>
        <!-- 将延迟加载开关打开 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 开启延迟加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    
  5. 测试

    SqlSession sqlSession=sqlSessionFactory.openSession();
    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    List<Order> orders=userMapper.findUserOrderLazyLoding();
    for (Order order : orders) {
        //查询相应的user
        System.out.println(order.getUser());
    }
    

查询缓存

mybatis提供查询缓存,用于减轻数据库压力。mybatis提供一级缓存和二级缓存。

  1. 一级缓存

    一级缓存是SqlSession级别的缓存。在操作数据库是需要构造SqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的SqlSession之间的缓存数据区域是互不影响的

  2. 二级缓存

    二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

一级缓存

默认打开

二级缓存

  1. 在SQLMapConfig.xml文件中将二级缓存打开

    <!-- 开启二级缓存 -->
    <setting name="cacheEnabled" value="true"/>
    
  2. 二级缓存的作用范围是Mapper的namespace下的,所以需要在Mapper文件中将二级缓存打开

    <!-- 开启二级缓存 -->
    <cache></cache>
    

    应用场景:请求次数多且用户对查询的实时性要求不高,如:耗时高的的统计分析SQL、电话账单查询等

实现方法:设置刷新间隔时间flushinterval

局限性:二级缓存对细粒度的数据级别的缓存实现不好

statement中禁止使用二级缓存

在statement中设置useCache=false可以禁用到钱select语句的二级缓存,即每次查询都会发出SQL去查询,默认情况是TRUE

<select id="findUserOrderLazyLoding" resultMap="UserOrderLazyLodingResultMap" useCache="false">

刷新缓存

在select、update、insert执行(commit)的后需要执行刷新缓存(即清空缓存),否则可能会读到脏数据。

mybatis和Spring整合–原始dao开发

  1. 导入jar包,包括mybatis-spring.jar(注意版本号)
  2. 在Spring配置文件中配置SqlSessionFactory,和dao

    <!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:db.properties" />
    
    <!-- 配置c3p0数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 注入属性值 -->
        <property name="driverClass" value="${jdbc.drivername}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <!-- 配置SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
        <!-- 加载mybatis配置文件 -->
        <property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
        <!-- 配置数据源 -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置UserDao -->
    <bean id="userDao" class="cn.zcw.ssm.dao.UserDaoImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>
    
  3. UserDaoImpl代码

    SqlSession sqlSession=this.getSqlSession();
        User user=sqlSession.selectOne("test.findUserById", id);
        return user;
    }
    

spring-mybatis整合–mapper代理开发

  1. 逐个配置mapper

    <!-- mapper配置 
        此方法需要对每一个mapper进行配置,麻烦
    -->
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        mapperInterface指定mapper接口
        <property name="mapperInterface" value="cn.zcw.mapper.UserMapper"></property>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>
    
  2. 扫描mapper(建议)

    <!-- mapper批量扫描,从mapper包中扫描出mapper接口,自动创建代理对象并且在Spring容器中注册
        遵循规范:将mapper.java和mapper.xml映射文件的名称保持一致,且在同一目录
        自动扫描出来的mapper的bean的id为mapper类名,首字母小写
     -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- basePackage:
            要扫描的包名,如果要扫描多个包,可用逗号隔开
         -->
        <property name="basePackage" value="cn.zcw.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值