zoukankan      html  css  js  c++  java
  • MyBatis框架之入门(三)

    使用原始dao层进行开发

    UserMapper层接口

    public interface UserMapper {
        /**
         * 通过id查询用户
         * @param id
         * @return
         */
        User queryUserById(Integer id);
    }

    UserMapper层的实现类

    public class UserMapperImpl implements UserMapper{
    
        private SqlSessionFactory sqlSessionFactory;
    //使用构造方法进行注入sqlSessionFactory
        public UserMapperImpl(SqlSessionFactory sqlSessionFactory) {
            this.sqlSessionFactory = sqlSessionFactory;
        }
    
        /**
         * 通过id查询用户
         *
         * @param id
         * @return
         */
        @Override
        public User queryUserById(Integer id) {
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            User user = (User)sqlSession.selectOne("test.queryUserById", 2);
    
            return user;
        }
    }

    测试类

     */
    public class DaoTest {
        @Test()
        public void daoTest() throws IOException {
            InputStream inputStream = Resources.getResourceAsStream("SqlMapperConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            UserMapperImpl userMapper = new UserMapperImpl(sqlSessionFactory);
            User user = userMapper.queryUserById(2);
            System.out.println(user);
        }
    }

    最后的结果为:

    使用动态代理进行开发.

        定义一个Mapper接口,这个接口其实和我们UserDao接口是一样的,从Mybatis框架中拿到一个代理对象(代理的是这个Mapper接口),通过代理对象调用接口当中的方法完成业务.

     传统dao开发方式中的实现类其实起了一个连接,承上启下的作用,连接了接口和xml映射文件,效果就是调用接口中方法时能够找到xml映射文件.

       Mapper动态代理开发遵从的规范:

          1.sql映射文件的namespace必须和mapper接口的全限定类名保持一致

          2.mapper接口的接口方法名必须和xml中的sql语句id保持一致.

          3.mapper接口的接口方法形参类型必须和sql语句的输入参数类型保持一致

          4.mapper接口的接口方法返回类型必须和sql语句的resultType保持一致

    UserMapper接口

    public interface UserMapper {
        User queryUserById(Integer id);
    }

    UserMapper.xml配置文件

    <!-- namespace属性值=接口全限定名-->
    <mapper namespace="com.itheima.mapper.UserMapper">
       <!-- id属性值=方法名-->
       <select id="queryUserById" parameterType="Integer" resultType="com.itheima.pojo.User">
          select * from user where id=#{id}
      </select>
    </mapper>

    测试类

    @Test
    public void userMapper() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(2);
        System.out.println(user);
    }

    总结:关于使用动态代理,就是将不用通过

    UserMapperImpl userMapper = new UserMapperImpl(sqlSessionFactory);这个方法获取到UserMapper对象,然后再操作里面的方法,
    而是通过
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);这个方法获取到动态代理对象,间接的操作这个类里面的方法.
    然后达到目的.

    全局properties的配置

    重新创建一个db.properties文件

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.user=root
    jdbc.password=root

    将这个文件引入到SqlMapperConfig.xml中

    <properties resource="db.properties"></properties>

    然后修改SqlMapperConfig.xml文件

           <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.user}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>

    <typeAliases>
        <!-- 为pojo对象定义别名-->
        <typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>
    </typeAliases>
    <!-- 使用别名即可-->
    <select id="queryUserById" parameterType="int" resultType="User">
       select * from user where id=#{id}
    </select>

    扫描所有pojo包下的类。注意:不可以出现相同的类名

    <typeAliases>
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- 自动扫描pojo包下的全部类-->
        <package name="com.itheima.pojo" ></package>
    </typeAliases>

    全局配置文件mappers

    mappers注册sql映射文件的

    • resource属性加载sql映射文件,万能型选手(crud、原始dao、mapper动态代理)

    • 针对Mapper动态代理进行一个增强(增强两种用法)

    • mapper class 单个注册

    • package 批量扫描注册

    • 以上两种方式有规范要求

    <mappers>
        <mapper resource="sqlmapper/UserMapper.xml" />
        <mapper resource="mapper/UserMapper.xml" />
        <mapper class="com.itheima.mapper.UserMapper"></mapper>
        <package name="com.itheima.mapper"></package>
    </mappers>

    MyBatis输入参数类型

    parameterType(输入参数类型)

    1.传递简单类型

    2.传递Pojo对象

    3.传递Pojo包装对象

    QueryVO类

    public class QueryVo {
        private User user;
        public User getUser() {
            return user;
        }
        public void setUser(User user) {
            this.user = user;
        }
    }

    UserMapper接口

    public interface UserMapper {
        User queryUserById(Integer id);
        List<User> queryUserByQueryVo(QueryVo queryVo);
    }

    UserMapper接口类  传入的参数为queryVO,然后查询时候,需要使用User类中的username通过#{user.username}获取

    <select id="queryUserByQueryVo" resultType="user" parameterType="queryvo">
       select * from user where username like #{user.username}
    </select>

    Test测试类

    @Test
    public void userMapperQueryVo(){
           //       获取到工厂建造者对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    //        通过本类加载器获取到一个流对象,这个流对象用来读取SqlMapperConfig.xml文件
            InputStream inputStream = SqlMapperTest.class.getClassLoader().getResourceAsStream("sqlMapperConfig.xml");
    //        创建工厂对象
            sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    
        SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取到映射对象,getMapper("实现类",接口.class)
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        QueryVo queryVo = new QueryVo();
        User user = new User();
    //将要查询的东西,封装在user类中
        user.setUsername("%王%");
        queryVo.setUser(user);
        List<User> list = mapper.queryUserByQueryVo(queryVo);
        for(User u :list){
            System.out.println(u);
        }
        sqlSession.close();
    }

    MyBatis的手动映射

    当数据库中的列名和domain类中的属性名,不能对应上的时候,就会出现封装数据失败,mybatis无法将数据表中数据准确的封装到domain对象中,因此必须使用手动映射方式,

    domain类

    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;

    Mapper接口

    public interface OrdersMapper {
        List<Orders> queryOrders();
    }

    xml配置文件

    <mapper namespace="com.itheima.mapper.OrdersMapper">
       <select id="queryOrders" resultMap="order">
          select * from orders
       </select>
       <!-- id属性值=resultMap属性值-->
       <resultMap id="order" type="com.itheima.pojo.Orders">
          <!-- 配置pojo对象红的属性名和数据表列名的对应关系 --> 
          <id property="id" column="id"></id>
          <result property="userId" column="user_id"></result>     //property 为domian中的属性名,column为数据库中的列名
          <result property="number" column="number"></result>
          <result property="createtime" column="createtime"></result>
          <result property="note" column="note"></result>
    
       </resultMap>
    </mapper>

    Test测试类

    @Test
    public void ordersMapper(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapper ordersMapper  = sqlSession.getMapper(OrdersMapper.class);
        List<Orders> list = ordersMapper.queryOrders();
        for(Orders orders : list){
            System.out.println(orders);
        }
        sqlSession.close();
    }

     MyBatis连接池

    在Mybatis的配置文件中,这个位置配置了数据源,,也就是使用了连接池.

    那么连接池是在什么时候建立的,什么时候从连接池中获取连接的.

    连接池初始化的时机:

    在SqlSessionFactoryBuilder构建SqlSessionFactory的时候初始化的连接池,初始化之后,放入Configuration对象中,分析框架的源代码:

    org.apache.ibatis.builder.xml.XMLConfigBuilder类的方法environmentsElement()

    什么时候从连接池中获取连接

    在getMapper的时候是不会从数据库连接池中获取数据库连接的,在具体操作数据库调用mapper接口方法的时候才会从连接池拿连接.

    UNPOOLED:不适用数据库连接池(一般情况下不使用)

    JNDI:(前提是你的Mybatis环境必须是Web应用)

    什么是JNDI?

    JNDI:java naming directory interface(java命名目录接口,它是一种服务发布技术),数据源可以以服务的形式发布出去,那么哪个应用想用,就类似于客户端调用远程服务一样去调用即可.

    为什么必须是wen应用?

    往往只有tomcat./weblogic服务中间件才支持JNDI技术.

    如果Mybatis当中用,怎么用?

    第一步:在数据库驱动程序(jar包)放到tomcat安装目录下的lib文件夹下.

    第二步:在Tomcat的conf/context.xml文件中进行jndi数据源服务配置

    <Resource name="jndi/mybatis" auth="Container"
    type="javax.sql.DataSource"
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/mybatis?
    characterEncoding=utf8"
      username="root" password="root"
    maxActive="20"
    maxIdle="10"
    maxWait="10000">
    </Resource>

    name:在JNDI中叫做目录名,等同于服务名,此处的jndi/mybatis是自定义的,往往以/连接前后字符串即可。auth和type是固定的,其他都是数据库连接池的具体配置信息。

    第三步 :在自己web项目的web.xml中引用Jndi数据源服务。

    <resource-ref>
    <res-ref-name>jndi/mybatis</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
     </resource-ref>

    第四步:在自己web项目的Mybatis配置文件中使用

    <property name="data_source"
    value="java:comp/env/jndi/mybatis"/>

    配置data_source属性,指向你的数据源引用,java:comp/env/jndi/mybatis中红色部分是固定的,绿色部分是你自己定义的目录名(服务名)。
    MyBatis事务控制

    通过sqlSession.openSession这种方法操作数据库时候,mybatis默认把事务自动提交给关闭了,注意:数据量非常小可以自动提交,数据量大就应该手动提交。自动提交在openSession
    方法中传入参数true: SqlSession sqlSession = sqlSessionFactory.openSession(true)
    动态SQL标签

    where和if标签

    需求:根据用户的性别和用户名多条件查询用户信息

    <select id="queryUserByWhere" resultType="user" parameterType="user">
     select * from user where sex=#{sex} and username like #{username}
    </select>
    @Test
    public void queryUserByWhere(){
      SqlSession sqlSession = sqlSessionFactory.openSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      User user = new User();
      user.setSex("2");
      user.setUsername("%王%");
      List<User> list = mapper.queryUserByWhere(user);
      if(list!=null && list.size()>0){
        for(User user1 : list){
          System.out.println(user1);
       }
     }
    }

    以上查询是可以查询到相关的数据的,假定不传递sex的值,那么就会出现什么也差不到的结果?

    通过日志可以看出,MyBatis在执行SQL语句的时候,参数sex的值是null,因此没有查询到结果。在以往的做法是判断参数是否为空,并进行字符串的拼接。在MyBatis框架中,提供了where标签和if标签来实现动态SQL语句。
    where标签:处理SQL语句,自动添加where关键字,并去掉紧跟他后面的一个and或者or

    if标签:test属性,判断表达式真假

    <select id="queryUserByWhere" resultType="user"
    parameterType="user">
     select * from user
     <where>
       <if test="sex!=''and sex!=null">
        and sex=#{sex}
       </if>
       <if test="username!=''and username!=null">
        and username like #{username}
       </if>
     </where>
    </select>

    SQL标签

    将SQL语句抽取,其他SQL语句中引入

    <!--
     SQL片段抽取
     使用include标签引入
    -->
    <sql id="commonsSql">
     id,username,sex,birthday,address
    </sql>

    引入外部xml配置文件中的共享SQL片段时,使用namespace属性值+“.”+sql标签的id属性值。

    foreach标签传入集合

    删除多条数据的SQL语句,delete from user where id in(1,2,3)

    String sql = "delete from user where id in("
    for(int i=0; i<list.size();i++) {
    if(i != list.size()-1)
    sql += list.get(i) + ","
    else
     sql += list.get(i)+")"
    }

    foreach标签遍历拼接SQL语句

      collection属性:遍历传入的集合,当参数是集合时collection属性值固定为list

      open属性:遍历拼接前
      close属性:遍历拼接后
      separator属性:拼接的符号
      item属性:遍历到的元素

    <select id="queryUserByIdsList" parameterType="list"
    resultType="user">
      select * from user
       <foreach collection="list" open="where id in(" close=")"
    separator="," item="item">
        #{item}
       </foreach>
     </select>
    @Test
    public void queryUserByIdsList(){
      SqlSession sqlSession = sqlSessionFactory.openSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      List<Integer> idsList = new ArrayList<Integer>();
      idsList.add(1);
      idsList.add(2);
      idsList.add(3);
      List<User> list = mapper.queryUserByIdsList(idsList);
      if(list!=null && list.size()>0){
        for (User user : list){
          System.out.println(user);
       }
     }
      sqlSession.close();
    }

    foreach标签传入数组

    foreach标签遍历拼接SQL语句
      collection属性:遍历传入的集合,当参数是数组时collection属性值固定为array
      open属性:遍历拼接前
      close属性:遍历拼接后
      separator属性:拼接的符号
      item属性:遍历到的元素

    <select id="queryUserByIdsArray" parameterType="int[]"
    resultType="user">
     select * from user
     <foreach collection="array" open="where id in(" close=")"
    separator="," item="item">
      #{item}
     </foreach>
    @Test
    public void queryUserByIdsArray(){
      SqlSession sqlSession = sqlSessionFactory.openSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      int[] idsArray= {1,2,3};
      List<User> list = mapper.queryUserByIdsArray(idsArray);
      if(list!=null && list.size()>0){
        for (User user : list){
          System.out.println(user);
       }
     }
      sqlSession.close();
    }

    foreach标签传入pojo对象

    foreach标签遍历拼接SQL语句
      collection属性:遍历传入的pojo对象中的集合,collection属性配置pojo中成员变量名
      open属性:遍历拼接前
      close属性:遍历拼接后
      separator属性:拼接的符号
      item属性:遍历到的元素

    public class QueryVo {
      private List<Integer> idsList;
      public List<Integer> getIdsList() {
        return idsList;
     }
      public void setIdsList(List<Integer> idsList) {
        this.idsList = idsList;
     }
    }
    <select id="queryUserByQueryVo" parameterType="queryVo"
    resultType="user">
     select * from user
     <foreach collection="idsList" open="where id in(" close=")"
    separator="," item="item">
      #{item}
     </foreach>
    </select>
    @Test
    public void queryUserByQueryVo(){
      SqlSession sqlSession = sqlSessionFactory.openSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      QueryVo queryVo = new QueryVo();
      List<Integer> idsList = new ArrayList<Integer>();
      idsList.add(1);
      idsList.add(2);
      idsList.add(3);
      queryVo.setIdsList(idsList);
      List<User> list = mapper.queryUserByQueryVo(queryVo);
      if(list!=null && list.size()>0){
        for (User user : list){
          System.out.println(user);
       }
     }
      sqlSession.close();
    }
  • 相关阅读:
    Admin注册和路由分发详解
    自定义Xadmin
    苑昊老师的博客
    pip 国内源 配置
    Django模型层(2)
    Django 中间件
    Django form表单
    整理的最全 python常见面试题(基本必考)
    AJAX
    Cookie、Session和自定义分页
  • 原文地址:https://www.cnblogs.com/qingmuchuanqi48/p/10634393.html
Copyright © 2011-2022 走看看