java mybatis学习之$和#区别,mapper代理接口,动态SQL,在日志中输出mybatis的sql语句

1.在mybatis中,$和#的区别:

#{}:表示一个预处理参数,参数类型不定,是根据传入的参数类型来设定的。类似于JDBC中的?

特例使用,模糊查询:(针对oracle):

and username like concat(concat(‘%‘,#{username}),‘%‘)

${}:相当于是我们的JDBC里的字符串拼接。这里就相当于传入的就是一个字符串(不管传入什么样的数据类型,都是字符串)

and username like ‘%${value}%‘

2.$和#在mybatis中的优缺点:

#{}:传进去的值可以设置其数据类型。会根据传入的数据类型自动加字符串的单引号或者不加单引号。预处理参数。可以防止SQL注入。

${}:采取的$的方式传入参数,所有采取$的方式传入的参数都只是字符串(无论传入的是什么,都会当成字符串处理),潜在的危险就是SQL注入的问题。而${}的优势在于字符串的拼接可以处理sql语句的一些特殊情况,例如:

默认情况下,使用#{}格式的语法会导致 MyBatis 创建预处理语句属性并以它为背景设 置安全的值(比如?) 。这样做很安全,很迅速也是首选做法,有时你只是想直接在 SQL 语 句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用:

ORDER BY ${columnName}

3.mapper代理接口和动态SQL

直接上代码:

这是测试的代码

 1 package com.jinglin.hotelsup.test;
 2
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.util.List;
 6
 7 import org.apache.ibatis.io.Resources;
 8 import org.apache.ibatis.session.SqlSession;
 9 import org.apache.ibatis.session.SqlSessionFactory;
10 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
11 import org.apache.log4j.Logger;
12 import org.junit.Test;
13
14 import com.jinglin.hotelsup.dao.impl.UserInfoDao;
15 import com.jinglin.hotelsup.mapper.UserInfoMapper;
16 import com.jinglin.hotelsup.model.UserInfo;
17
18 public class TestUserInfo {
19
20     //日志
21     static Logger logger = Logger.getLogger(TestUserInfo.class);
22     //定义一个工厂
23     static SqlSessionFactory factory = null;
24     //静态块
25     static{
26         InputStream inputStream = null;
27         try {
28             inputStream =         Resources.getResourceAsStream("mybatis-config.xml");
29         } catch (IOException e) {
30             // TODO Auto-generated catch block
31             e.printStackTrace();
32             logger.error("创建连接对象出错,错误信息:"+e.getMessage());
33         }
34         factory = new SqlSessionFactoryBuilder().build(inputStream);
35     }
36
37     @Test
38     public void test(){
39         SqlSession session = factory.openSession();
40         //代理的接口
41         UserInfoMapper userInfoMapper = session.getMapper(UserInfoMapper.class);
42         //添加
43         /*UserInfo userInfo = new UserInfo();
44         userInfo.setUsername("张三3号");
45         //userInfo.setUserpwd("123456");
46         userInfo.setJob("程序员");
47         //userInfo.setCard("521354499653159894");
48         int count = userInfoMapper.insertItem(userInfo);
49         //事务提交
50         session.commit();
51         //关闭
52         session.close();
53         System.out.println("受影响行数:"+count);
54         System.out.println("刚刚插入的主键:"+userInfo.getUserid());*/
55
56         //修改
57         /*UserInfo userInfo = new UserInfo();
58         userInfo.setUsername("张三1号");
59         userInfo.setUserpwd("123456");
60 //        userInfo.setJob("程序员");
61 //        userInfo.setCard("521354499653159894");
62         userInfo.setUserid(21);
63         int count = userInfoMapper.updateItem(userInfo);
64         //事务提交
65         session.commit();
66         //关闭
67         session.close();
68         System.out.println("受影响行数:"+count);*/
69
70         //逻辑删除
71         /*UserInfo userInfo = new UserInfo();
72         userInfo.setUserid(21);
73         int count = userInfoMapper.deleteItem(userInfo);
74         //事务提交
75         session.commit();
76         //关闭
77         session.close();
78         System.out.println("受影响行数:"+count);*/
79
80         //查询多条
81         /*UserInfo userInfo = new UserInfo();
82         //userInfo.setUsername("张三");
83         List<UserInfo> list = userInfoMapper.selectAll(userInfo);
84         for (UserInfo u : list) {
85             System.out.println(u.getUsername()+"\t"+u.getUserpwd());
86         }*/
87
88         //模糊查询
89         /*UserInfo userInfo = new UserInfo();
90         userInfo.setUsername("张");
91         List<UserInfo> list = userInfoMapper.getDimList(userInfo);
92         for (UserInfo u : list) {
93             System.out.println(u.getUsername()+"\t"+u.getUserpwd());
94         }*/
95     }
96 }

mybatis-config配置

<?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>
    <settings>
        <!-- 通过日志记录显示mybatis的执行过程 -->
        <setting name="logImpl" value="LOG4J"/>
     </settings>
    <!-- 定义别名 -->
    <typeAliases>
        <typeAlias type="com.jinglin.hotelsup.model.UserInfo" alias="UserInfo"/>
    </typeAliases>
    <!-- 定义多个配置环境 -->
    <environments default="development">
        <!-- 定义其中一个配置环境 -->
        <environment id="development">
            <!-- 定义事务处理类型 -->
            <transactionManager type="JDBC"/>
            <!-- 定义数据源 -->
            <dataSource type="POOLED">
            <!-- 数据库驱动名称 -->
            <property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
               <!-- 数据库URL地址 -->
               <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
               <!-- 数据账号 -->
               <property name="username" value="hotelmanager"/>
               <!-- 数据库密码 -->
               <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
    <mapper resource="com/jinglin/hotelsup/mapper/UserInfoMapper.xml"/>
    </mappers>
</configuration>

dao层的接口

package com.jinglin.hotelsup.dao;

import java.util.List;

public interface IDaoHotelsup<T> {
    public int insertItem(T t);//添加一条数据
    public int updateItem(T t);//修改一条数据
    public T selectById(T t);//根据id查询单条
    public int deleteItem(T t);//删除一条数据
    public List<T> selectAll(T t);//查询全部
    public List<T> getDimList(T t);//模糊查询
}

mapper接口,在这里是接口继承了接口

package com.jinglin.hotelsup.mapper;

import com.jinglin.hotelsup.dao.IDaoHotelsup;
import com.jinglin.hotelsup.model.UserInfo;

public interface UserInfoMapper extends IDaoHotelsup<UserInfo>{

}

mapper的映射

<?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.jinglin.hotelsup.mapper.UserInfoMapper">
    <!-- 定义重复使用的代码段 -->
    <sql id="selectColumns">
        select * from userinfo where del=‘N‘
    </sql>
    <!-- 添加 -->
    <insert id="insertItem" parameterType="UserInfo" useGeneratedKeys="true" keyColumn="userid" keyProperty="userid">
       insert into userinfo
       <trim prefix="(userid," suffixOverrides=",">
         <if test="username != null">
             username,
         </if>
         <if test="userpwd != null">
             userpwd,
         </if>
         <if test="card != null">
             card,
         </if>
         <if test="job != null">
             job
         </if>
       </trim>
       <trim prefix=")values(usersid.nextval,">
         <if test="username != null">
                #{username},
         </if>
         <if test="userpwd != null">
             #{userpwd},
         </if>
         <if test="card != null">
             #{card},
         </if>
         <if test="job != null">
             #{job}
         </if>
       </trim>
      )
    </insert>

    <!-- 修改 -->
    <update id="updateItem" parameterType="UserInfo">
        update userinfo
        <set>
          <if test="username != null">
            username=#{username},
          </if>
          <if test="userpwd != null">
            userpwd=#{userpwd},
          </if>
          <if test="card != null">
              card=#{card},
          </if>
          <if test="job != null">
              job=#{job}
          </if>
        </set>
        where userid=#{userid}
    </update>

    <!-- 删除 -->
    <delete id="deleteItem" parameterType="UserInfo">
        <!-- delete from userinfo where userid=#{userid} -->
        <!-- 逻辑删除 -->
        update userinfo set del=‘Y‘ where userid=#{userid}
    </delete>

    <!-- 根据id查询 -->
    <select id="selectById" resultType="UserInfo" parameterType="UserInfo">
           <include refid="selectColumns"></include>
           and userid=#{userid}
    </select>

    <!-- 查询全部 -->
    <select id="selectAll" resultType="UserInfo">
           <include refid="selectColumns"></include>
           <if test="username != null and username != ‘‘">
           and username=#{username}
           </if>
           <if test="userpwd != null and userpwd != ‘‘">
        and userpwd=#{userpwd}
        </if>
           <if test="card != null and card != ‘‘">
        and card=#{card}
        </if>
           <if test="job != null and job != ‘‘">
        and job=#{job}
        </if>
    </select>

    <!-- 迷糊查询-->
    <select id="getDimList" resultType="UserInfo" parameterType="UserInfo">
        <include refid="selectColumns"></include>
        <if test="username != null and username != ‘‘">
           and username like concat(concat(‘%‘,#{username}),‘%‘)
           </if>
           <if test="userpwd != null and userpwd != ‘‘">
        and userpwd like concat(concat(‘%‘,#{userpwd}),‘%‘)
        </if>
           <if test="card != null and card != ‘‘">
        and card like concat(concat(‘%‘,#{card}),‘%‘)
        </if>
           <if test="job != null and job != ‘‘">
        and job like concat(concat(‘%‘,#{job}),‘%‘)
        </if>
    </select>
</mapper>

以下是日志文件显示SQL语句

首先,注意mybatis-config中的log4j的<setting>标签

<settings>
        <!-- 通过日志记录显示mybatis的执行过程 -->
        <setting name="logImpl" value="LOG4J"/>
     </settings>

其次,是log4j部分

#将ibatis log4j运行级别调到DEBUG可以在控制台打印出ibatis运行的sql语句
log4j.rootLogger=debug,stdout,logfile
### 把日志信息输出到控制台 ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
### 把日志信息输出到文件:jbit.log ###
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=F:/logs/test.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
###显示SQL语句部分
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

显示SQL语句部分则是实现将sql语句显示出来的关键,实现结果如下

接下来是动态SQL的详解,

动态SQL,顾名思义就是将SQL语句动态化,区别与传统的SQL语句。动态SQL语句的优势在于它的灵活,在开发项目的过程中可以减少代码量

MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空 格或在列表的最后省略逗号。动态 SQL 可以彻底处理这种痛苦。

if

在动态 SQL 中所做的最通用的事情是包含部分 where 字句的条件。比如:

<select id="findActiveBlogWithTitleLike"
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

这条语句会提供一个可选的文本查找功能。如果你没有传递 title,那么所有激活的博客 都会被返回。但是如果你传递了 title,那么就会查找相近的 title(对于敏锐的检索,这中情 况下你的参数值需要包含任意的遮掩或通配符)的博客。

假若我们想可选地搜索 title 和 author 呢?首先,要改变语句的名称让它有意义。然后 简单加入另外的一个条件。

<select id="findActiveBlogLike"
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

choose, when, otherwise

有时我们不想应用所有的条件, 相反我们想选择很多情况下的一种。 Java 中的 switch 和 语句相似,MyBatis 提供 choose 元素。

我们使用上面的示例,但是现在我们来搜索当 title 提供时仅有 title 条件,当 author 提 供时仅有 author 条件。如果二者都没提供,只返回 featured blogs(也许是由管理员策略地选 择的结果列表,而不是返回大量没有意义的随机博客结果列表)。

<select id="findActiveBlogLike"
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

trim, where, set

前面的例子已经方便地处理了一个臭名昭著的动态 SQL 问题。要考虑我们回到“if”示 例后会发生什么,但是这次我们将“ACTIVE = 1”也设置成动态的条件。

<select id="findActiveBlogLike"
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG
  WHERE
  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

如果这些条件都没有匹配上将会发生什么?这条 SQL 结束时就会成这样:

SELECT * FROM BLOG
WHERE

这会导致查询失败。如果仅仅第二个条件匹配是什么样的?这条 SQL 结束时就会是这 样:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

这个查询也会失败。这个问题不能简单的用条件来解决,如果你从来没有这样写过,那 么你以后也不会这样来写。

MyBatis 有一个简单的处理,这在 90%的情况下都会有用。而在不能使用的地方,你可 以自定义处理方式。加上一个简单的改变,所有事情都会顺利进行:

<select id="findActiveBlogLike"
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

where 元素知道如果由被包含的标记返回任意内容,就仅仅插入“WHERE” 。而且,如 果以“AND”或“OR”开头的内容,那么就会跳过 WHERE 不插入。

如果 where 元素没有做出你想要的,你可以使用 trim 元素来自定义。比如,和 where 元素相等的 trim 元素是:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 属性采用管道文本分隔符来覆盖, 这里的空白也是重要的。 它的结果就是移除 在 prefixOverrides 属性中指定的内容,插入在 with 属性中的内容。

和动态更新语句相似的解决方案是 set。set 元素可以被用于动态包含更新的列,而不包 含不需更新的。比如:

<update id="updateAuthorIfNecessary"
       parameterType="domain.blog.Author">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

这里,set 元素会动态前置 SET 关键字,而且也会消除任意无关的逗号,那也许在应用 条件之后来跟踪定义的值。

如果你对和这相等的 trim 元素好奇,它看起来就是这样的:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

注意这种情况下我们覆盖一个后缀,而同时也附加前缀。

时间: 2024-10-23 19:16:00

java mybatis学习之$和#区别,mapper代理接口,动态SQL,在日志中输出mybatis的sql语句的相关文章

开发中遇到的问题---【使用mybatis时 有一个sql查询不到结果 日志也显示查询为o 但是从日志中取出执行的sql到数据库客户端手动执行,可以查到数据】

问题:使用mybatis时 有一个sql查询不到结果 日志也显示查询为o 但是从日志中取出执行的sql到数据库客户端手动执行,可以查到数据: 原因:MyBatis看到 #{}会认为你在给sql中的变量赋值,就像JDBC编程中给问号赋值一样(自动在前后加单引号)也就是说,他把你传入的字符串并没有当做多个值,而是当做一个大的字符串,所以查询不到值 而MyBatis看到${}的时候会直接将之替换成变量的值而不做任何处理: 解决方案:将查询条件中的“#”替换成“$”. <select id="fi

Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发(转发同上)

前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(一)--MyBatis的基础知识.MybatisFirst中存在大量重复的代码.这次简化下代码: 原地址:http://www.cnblogs.com/shanheyongmu/p/7121016.html 使用MyBatis开发Dao,通常有两种方法,即原始Dao开发方法和Mapper接口开发方法. 1.SqlSession使用范围 1.1 SqlsessionFactoryBuilder 通过SqlSessionFac

Mybatis 和Spring整合之mapper代理开发

F:\1ziliao\mybatis\代码 1.1 SqlMapConfig.xml <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <conf

Mybatis入门---dao开发和mapper代理开发

在说mabatis之前,先说说单独使用jdbc编程的缺陷. jdbc编程的大概流程大家都很清楚,基本分为以下几步: 加载数据驱动 创建并获取数据库连接 创建jdbc statement对象 设置sql语句,并设置sql语句中的参数 通过statement执行sql并获取结果 对执行的结果进行解析处理 释放资源 1 public static void main(String[] args) { 2 Connection connection = null; 3 PreparedStatement

Java反射学习总结三(静态代理)

反射最常见的应用就是代理模式了. 本文先简单介绍一下代理模式,并写一个静态代理的例子.为下一篇重要的动态代理做点铺垫 代理模式的作用是: 为其他对象提供一种代理以控制对这个对象的访问. 另外在某些情况下,一个客户不想或着不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 说白了,代理模式就是一个"中介",他有这客户们的引用,所以可以用这个"中介"来代替客户来做操作. 代理模式设计的角色: 想使用代理模式,需要定义如下的3个角色: 抽象角色:

java核心学习(四十) 使用反射生成JDK动态代理

java.lang.reflect包下提供了一个Proxy类和InvocationHandler接口,用于生成动态代理类和动态代理对象. 一.使用Proxy.InvocationHandler创建动态代理 这里要注意,在java.net包下也有一个Proxy类,不过这个类是用于设置代理服务器的,莫混淆.. Proxy提供了如下两个方法创建动态代理类和动态代理实例: 实际上即使采用第一种方法创建动态代理类,如果程序需要通过该代理类来创建对象,依然需要传入一个InvocationHandler对象,

Mybatis学习总结(二)—使用接口实现数据的增删改查

在这一篇中,让我们使用接口来实现一个用户数据的增删改查. 完成后的项目结构如下图所示: 在这里,person代表了一个用户的实体类.在该类中,描述了相关的信息,包括id.name.age.id_num信息.而personMapper则是该实体类的一个配置文件.需要注意的是,在上一篇博文中,namespace属性的值是其本身,而在这一篇中,使用的是接口.那么两者有什么区别呢?使用接口,那么相关的操作方法不用自己去实现,只需要调用该接口的相关的方法就能够实现相应的功能. 那么,在这里就有一个问题,接

[原创]java WEB学习笔记48:其他的Servlet 监听器:域对象中属性的变更的事件监听器 (3 个),感知 Session 绑定的事件监听器(2个)

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

Android(java)学习笔记181:Android 服务的应用,在Activity中实现背景音乐播放

1.在android应用程序里,有一种没有UI的类(android.app.Service)——Service.简单来说,Service是一个 background process(背景程序),通过背景程序,可以实现一些不需要UI的功能,比如播放背景音乐. 下面是一个实现播放背景音乐的例程: 在上个工程的基础上,在Activity中添加音乐播放功能. 在工程中添加一个新类 VoiceService (File->New->Class): import android.app.Service;