zoukankan      html  css  js  c++  java
  • Mybatis学习

     一 Mybatis搭建核心架构

    配置文件

     1 <?xml version="1.0" encoding="UTF-8" ?>
    19 <!DOCTYPE configuration
    20     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    21     "http://mybatis.org/dtd/mybatis-3-config.dtd">
    22 
    23 <configuration>
    33   <environments default="development">
    34     <environment id="development">
    35       <transactionManager type="JDBC">
    36         <property name="" value=""/>
    37       </transactionManager>
    38       <!-- 加载驱动和连接 -->
    39       <dataSource type="UNPOOLED">
    40         <property name="driver" value="com.mysql.jdbc.Driver"/>
    41         <property name="url" value="jdbc:mysql://127.0.0.1:3306/micro_message"/>
    42         <property name="username" value="xxx"/>
    43         <property name="password" value="xxx"/>
    44       </dataSource>
    45     </environment>
    46   </environments>
    54 </configuration>

     在java代码中读配置文件,读mybatis配置文件的代码应该写在Dao层

    Mybatis相关知识

       Dao层需求

        对象能与数据库交互

        能执行SQL语句

       Mybatis中向Dao层提供对象的名字叫做SqlSession(核心对象)

       SqlSession的作用

        向SQL语句传入参数

        执行SQL语句

        获取执行SQL语句结果的能力

        事务的控制

      如何得到SqlSession

        通过配置文件获取数据库连接相关信息

        通过配置信息构建SqlSessionFactory

        通过SqlSessionFactory打开数据库会话

    创建一个可以获取SqlSession的类

     1 /**
     2  * 访问数据库类
     3  */
     4 public class DBAccess {
     5     /**
     6      * 
     7      * @return
     8      * @throws IOException 出现异常先往外抛,抛给DAO层去处理,因为DAO层需要捕获异常并在finally中关闭拿到的SqlSession
     9      * 
    10      * mybatis的SqlSession也是提供的供数据库的会话,其实是对JDBC的二次封装,因此拿到数据后也是需要关闭的
    11      */
    12     public SqlSession getSqlSession() throws IOException {
    13         //通过配置文件获取数据库连接信息    路径从src根路径下面开始算起
    14         Reader reader = Resources.getResourceAsReader("com/imooc/config/Configuration.xml");
    15         //通过配置信息构建一个SqlSessionFactory
    16         SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    17         //通过SqlSessionFactory打开一个数据库会话
    18         SqlSession sqlSession = SqlSessionFactory.openSession();
    19         return sqlSession;
    20     }
    21 }

     第一次测试getSqlSession()方法在line16处报错

    public class MessageDao {
        /**
         * 根据查询条件查询消息列表
         * @param command
         * @param description
         * @return
         */
        public List<Message> queryMessageList(String command,String description) {
            DBAccess dbAccess = new DBAccess();
            SqlSession sqlSession = null;
            //通过sqlSession执行SQL语句
            
            try {
                sqlSession = dbAccess.getSqlSession();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                sqlSession.close();
            }
            
            
            return null;
        }
        public static void main(String[] args) {
            MessageDao messageDao = new MessageDao();
            //测试queryMessageList是否能够否文数据库
            messageDao.queryMessageList("test","test");
        }
    }

     报错信息:Exception in thread "main" java.lang.NullPointerException

     原因:在mybatis的配置文件中没有注释掉<mappers>,尚未编写Message.xml

      <mappers>
        <mapper resource="com/imooc/config/sqlxml/Message.xml"/>
      </mappers>

    二 SQL基本配置与执行

    SQL配置文件的目的:将配置文件中的SQL语句提供给SqlSession,使其能读到并执行.

    SQL语句标签的id属性就是给这段SQL语句起了一个名字,以便java代码通过该名称去调用.多个SQL配置文件的id都不能重名.因此可以通过namespace为每一个配置文件起一个不同的名称,因为不同的namespace下相同的id是可以存在的,不会引起冲突.配置文件中的resultMap标签能够配置java对象和数据库字段的映射关系.

    三 动态SQL拼接

    怎么向SQL语句传参

      将查询条件封装为message对象,将查询条件传入SQL语句中  

    public List<Message> queryMessageList(String command,String description) {
            DBAccess dbAccess = new DBAccess();
            List<Message> messageList = new ArrayList<Message>();
            SqlSession sqlSession = null;
            try {
                Message message = new Message();
                message.setCommand(command);
                message.setDescription(description);
                sqlSession = dbAccess.getSqlSession();
                // 通过sqlSession执行SQL语句
                messageList = sqlSession.selectList("Message.queryMessageList", message);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if(sqlSession != null) {
                    sqlSession.close();
                }
            }
            return messageList;
        }

    配置文件怎么接收参数

      使用parameterType="com.imooc.bean.Message"指定传入的参数类型,用于接收参数,如果是lang包下面的则可以直接写类型,例如在传递String类型的时候就直接写String,而并非写全路径的类名

    <select id="queryMessageList" parameterType="com.imooc.bean.Message" resultMap="MessageResult">
        select ID,COMMAND,DESCRIPTION,CONTENT from MESSAGE
        <where>
            <if test="command != null and !&quot;&quot;.equals(command.trim())">
                and COMMAND=#{command}
            </if>
            <if test="description != null and !&quot;&quot;.equals(description.trim())">
                and DESCRIPTION like '%' #{description} '%'
            </if>
        </where>
      </select>

     OGNL表达式

      OGNL和EL表达式意义相同,在Strusts2和Mybatis中都有用到,在mybatis中OGNL用于从parameterType中取到值并进行处理.不管从哪个标签中进行取值都是取得java类型,所以根据java类型的不同取值写法也有所不同

      OGNL的一个强大功能就是不仅能从java对象中去取属性值,而且还可以调用java的方法,本例调用了equals和trim方法

    <if test="description != null and!&quot;&quot;.equals(description.trim())">
        and DESCRIPTION like '%' #{description} '%'
    </if>

    四 应用log4j调试动态SQL

      Mybatis可以通过日志将最终执行的SQL语句打印出来,达到调试SQL的目的

      log4j的配置文件为properties文件,其中的值都为键值对的形式.程序可以通过key得到配置文件中对应的value.

        log4j.rootLogger:配置实用log4j输出日志的时候输出的级别和位置,级别由低到高分别为debug,info,warn,error其中≥配置中的优先级的设置都会打印出来

      Console指的是输出的位置为控制台

        log4j.appender.Console=org.apache.log4j.ConsoleAppender:日志打印到控制台,如果需要打印到文件中,此处的类就需要换掉

        log4j.appender.Console.layout:value表示按照自己的想法去输出

        log4j.appender.Console.layout.ConversionPattern:定义的输出日志格式%d打印时间,%t打印线程名称,%-5p表示打印的级别,%c指的是输出的时候所处的类的全名

        log4j.logger.org.apache:个性化,覆盖第一行的信息设置 

    log4j.rootLogger=DEBUG,Console
    log4j.appender.Console=org.apache.log4j.ConsoleAppender
    log4j.appender.Console.layout=org.apache.log4j.PatternLayout
    log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
    log4j.logger.org.apache=INFO

    五 实现单条信息删除

    配置文件:

      做删除的SQL语句比较简单,通过外部传递参数所以需要添加parameterType="int",数据库里都是自增列的整形,因此此处选择java的int类型.当参数为基本类型的时候参数可以以#{_parameter}类型书写---------

      <delete id="deleteOne" parameterType="int">
          delete from MESSAGE where ID = #{_parameter}
      </delete>

    DAO层:

      参数选择int类型的ID

      /**
         * 单条删除
         */
        public void deleteOne(int id) {
            DBAccess dbAccess = new DBAccess();
            SqlSession sqlSession = null;
            try {
                sqlSession = dbAccess.getSqlSession();
                // 通过sqlSession执行SQL语句
                sqlSession.delete("Message.deleteOne", id);
                sqlSession.commit();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if(sqlSession != null) {
                    sqlSession.close();
                }
            }
        }

    Service层:

      创建维护Service,没有建删除Service,在没有框架的情况下,Servlet也没有封装的情况下,页面只要有一个动作就对应了而一个Servlet,Service是很多的,因此把相似的功能放在一个Service中,因此创建一个维护Service,将新增 修改的功能都放置其中.

     1 /**
     2  * 维护相关的业务功能
     3  */
     4 public class MaintainService {
     5     /**
     6      * 单条删除
     7      */
     8     public void deleteOne(String id) {
     9         if(id != null && !"".equals(id.trim())) {
    10             MessageDao messageDao = new MessageDao();
    11             messageDao.deleteOne(Integer.valueOf(id));
    12         }
    13     }
    14     
    15     /**
    16      * 批量删除
    17      */
    18     public void deleteBatch(String[] ids) {
    19         MessageDao messageDao = new MessageDao();
    20         List<Integer> idList = new ArrayList<Integer>();
    21         for(String id : ids) {
    22             idList.add(Integer.valueOf(id));
    23         }
    24         messageDao.deleteBatch(idList);
    25     }
    26 }

    Servlet层:

      使用过滤器可以将Servlet中的重复代码进行处理,将判断等逻辑代码不应该写在Servlet中,而是将其写在Service中,Servlet负责接收页面的值及向页面传输值,如果需要根据业务逻辑进行数据处理应该调用相应的Service.DAO层完成与数据库的交互,完成相应的SQL语句

     1 /**
     2  * 单条删除控制层
     3  */
     4 @SuppressWarnings("serial")
     5 public class DeleteOneServlet extends HttpServlet{
     6 
     7     @Override
     8     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
     9             throws ServletException, IOException {
    10         // 设置编码
    11         req.setCharacterEncoding("UTF-8");
    12         // 接受页面的值
    13         String id = req.getParameter("id");
    14         MaintainService maintainService = new MaintainService();
    15         maintainService.deleteOne(id);
    16         // 向页面跳转
    17         req.getRequestDispatcher("/List.action").forward(req, resp);
    18     }
    19     
    20     @Override
    21     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    22             throws ServletException, IOException {
    23         this.doGet(req, resp);
    24     }
    25 }

    WEB.xml

      完成Servlet之后,应该在web.xml之中配置映射

    1   <servlet>
    2       <servlet-name>DeleteOneServlet</servlet-name>
    3       <servlet-class>com.imooc.servlet.DeleteOneServlet</servlet-class>
    4   </servlet>
    5   <servlet-mapping>
    6       <servlet-name>DeleteOneServlet</servlet-name>
    7       <url-pattern>/DeleteOneServlet.action</url-pattern>
    8   </servlet-mapping>

    JSP改造:

      单条删除,找到foreach标签,删除操作需要向servlet提交并且传参,直接写地址使用问号传参.信息不想暴露的时候不能使用GET传参

    <c:forEach items="${messageList}" var="message" varStatus="status">                     
        <tr  <c:if test="${status.index % 2 != 0}">style='background-color:#ECF6EE;'</c:if>>
            <td><input type="checkbox"  name="id" value="${message.id}"/></td>              
            <td>${status.index + 1}</td>                                                    
            <td>${message.command}</td>                                                     
            <td>${message.description}</td>                                                 
            <td>                                                                            
                <a href="#">修改</a>&nbsp;&nbsp;&nbsp;                                        
                <a href="${basePath}DeleteOneServlet.action?id=${message.id}">删除</a>        
            </td>                                                                           
        </tr>                                                                               
    </c:forEach>                                                                            

     六 实现信息批量删除

    1 mybatis配置文件写法,separator=","用于在循环中添加逗号

    1 <delete id="deleteBatch" parameterType="java.util.List">
    2       delete from MESSAGE where ID in(
    3           <foreach collection="list" item="item" separator=",">
    4               #{item}
    5           </foreach>
    6       )
    7   </delete>

    2 dao层代码

     1 public void deleteBatch(List<Integer> ids) {
     2         DBAccess dbAccess = new DBAccess();
     3         SqlSession sqlSession = null;
     4         try {
     5             sqlSession = dbAccess.getSqlSession();
     6             // 通过sqlSession执行SQL语句
     7             sqlSession.delete("Message.deleteBatch", ids);
     8             sqlSession.commit();
     9         } catch (IOException e) {
    10             // TODO Auto-generated catch block
    11             e.printStackTrace();
    12         } finally {
    13             if(sqlSession != null) {
    14                 sqlSession.close();
    15             }
    16         }
    17     }

    3 servlet层,servlet接收前台的多值使用String[] ids = req.getParameterValues("id");按照数组形式接收,依赖于前端多个名字相同的控件

    /**
     * 批量删除控制层
     */
    @SuppressWarnings("serial")
    public class DeleteBatchServlet extends HttpServlet{
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            // 设置编码
            req.setCharacterEncoding("UTF-8");
            // 接受页面的值
            String[] ids = req.getParameterValues("id");
            MaintainService maintainService = new MaintainService();
            maintainService.deleteBatch(ids);
            // 向页面跳转
            req.getRequestDispatcher("/List.action").forward(req, resp);
        }
        
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            this.doGet(req, resp);
        }
    }

    七 常用标签

     1 where标签:帮助SQL语句输出where关键字

      a 当没有检索条件的时候就不输出where关键字,无条件检索.

      b 将拼出来的检索条件中的第一条前面的and或者or去掉.

      <select id="queryMessageList" parameterType="com.imooc.bean.Message" resultMap="MessageResult">
        select ID,COMMAND,DESCRIPTION,CONTENT from MESSAGE
        <where>
            <if test="command != null and !&quot;&quot;.equals(command.trim())">
                and COMMAND=#{command}
            </if>
            <if test="description != null and !&quot;&quot;.equals(description.trim())">
                and DESCRIPTION like '%' #{description} '%'
            </if>
        </where>
     </select>

    2 sql标签:相当于java中常量定义的概念

    3 set标签:用于代替sql语句中的set关键字,用于判断条件之后去掉最后一条set语句中的逗号

    4 trim标签:可以代替where和set标签,prefix为前缀,suffix为后缀需要输出的值. 

    5 choose标签:类似于java中的if else

    八 容易混淆的概念

     1 resultMap和resultType的区别与联系

      都是用于表示结果集和java对象之间的一种关系, 好让mybatis帮助我们处理结果集,将结果集放在java对象中,  当使用resultType的时候就不需要配置resultMap了,只需要通过名字即可,只要sql结果集中的列明和bean对象中的属性名相同的时候就表示它们之间有映射关系.结果集中的对应关系是大小写不敏感的.

      使用resultMap不需要保证结果集中的列名和java中的属性名相同, resultMap中的typeHandler属性可以保证数据库中的日期或者布尔表示以正确的形式封装到java对象中.

    2 parameterMap和parameterType的区别与联系

       parameterType它是指向一个java类型的并且与ognl表达式和#{}紧密相连,parameterMap需要指向一个使用parameterMap标签配置的映射关系的id, parameterMap表明参数中的列与数据库中的列之间的对应关系.

    3 总结

      以Map结尾的首先应该想到映射,因此首先想到的应该是映射关系,Type结尾的应该想到的是java类型

    4 #{}与${}

      都是写在sql语句中,成为sql语句的一部分,#{}会被mybatis变成一个预编译的?,然后再通过preparedStatement为?赋值为前台传输的变量,${}会直接将变量值拼接到sql语句的位置,所以可以看出${}是没有预编译效果的,它和java中的变量去拼接一个字符串的效果是一样的.在sql中不需要进行预编译的地方则只能使用${}

    九 常见问题解析

  • 相关阅读:
    团队冲刺03
    梦断代码 阅读笔记02
    团队冲刺02
    团队冲刺01
    周总结
    团队工作任务
    阅读笔记3
    梦断代码阅读笔记01
    周总结
    NABCD项目分析
  • 原文地址:https://www.cnblogs.com/dzj0712/p/9424943.html
Copyright © 2011-2022 走看看