#{}占位符与${}拼接符如何在MyBatis中使用
#{}占位符与${}拼接符如何在MyBatis中使用?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
1、关于#{}占位符
先来看以下的示例,该示例是MyBatis中的SQL映射配置文件(Mapper配置文件),在该配置中使用了#{}占位符。
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mappernamespace="test"> <!--根据用户编号,查询单个用户实体--> <selectid="findUserById"parameterType="int"resultType="com.pjb.mybatis.po.User"> SELECT*FROMtb_userWHEREid=#{id} </select> <!--新增用户--> <insertid="insertUser"parameterType="com.pjb.mybatis.po.User"> INSERTINTOtb_user(user_name,blog_url,remark) VALUES(#{userName},#{blogUrl},#{remark}); </insert> </mapper>
在SQL映射配置文章中,输入参数需要用占位符来标识对应的位置。
在传统的JDBC编程中,占位符用“?”来标识,然后在加载SQL之前按照“?”的位置设置参数。
而“#{}”在MyBatis中也代表一种占位符,该符号接受输入参数,在大括号中编写参数名称来接受对应参数。
“#{}”接受的输入参数的类型可以是简单类型、普通JavaBean或者HashMap。
当接受简单类型时,“#{}”中可以写“value”或者其他任意名称。
如果接受的是JavaBean,它会通过OGNL读取对象中的属性值。
2、关于${}拼接符
再来看以下的示例,该示例是MyBatis中的SQL映射配置文件(Mapper配置文件),在该配置中使用了${}拼接符。
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mappernamespace="test"> <!--根据用户名称,模糊查询用户列表--> <selectid="findUserByUserName"parameterType="java.lang.String"resultType="com.pjb.mybatis.po.User"> SELECT*FROMtb_userWHEREuser_nameLIKE'%${value}%' </select> </mapper>
在SQL映射配置文件中,有时候需要拼接SQL语句。例如在模糊查询的时候,就需要在查询条件的两侧拼接两个“%”字符串,这个时候如果使用“#{}”占位符是不行的。在MyBatis中,“${}”在SQL配置文件中代表一个“拼接符号”,可以在原有SQL语句上拼接新的符合SQL语法的语句。
但是要注意的是,使用“${}”拼接的SQL语句,会引起SQL注入,所以一般不建议使用“${}”。
“${}”接受输入参数的类型可以是简单类型、普通JavaBean或者HashMap。
当接受简单类型时,“${}”中只能写“value”,而不能写其他任意名称。
如果接受的是JavaBean,它会通过OGNL读取对象中的属性值。
另外,在MyBatis 3.4.2之后,还可以在“${}”拼接符中设置一个默认值,格式如下:
${属性:默认值}
即在所需引入的属性名的后面添加“:”引号,然后紧跟着填写属性不存在或为空时的默认值。
【示例】设置“${}”拼接符的默认值。
(1)创建数据库连接的属性文件(db.properties)
在src目录下创建db.propertie属性文件,并使用“#”符号将属性项jdbc.username和jdbc.password注释掉,表示这两个属性项未进行配置。
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/db_admin?useSSL=false& #jdbc.username=root #jdbc.password=123456
(2)启用拼接符默认值的配置
要使用“${}”拼接符中设置一个默认值,需要在properties标签中设置启用拼接符默认值的配置项。
在MyBatis配置文件(mybatis-config.xml)中,使用<properties>标签加载数据库连接属性文件(db.properties),并在该标签中设置启用拼接符默认值的配置项,该配置如下:
<!--加载用于数据库配置的属性文件--> <propertiesresource="db.properties"> <!--启用默认值特性,这样${}拼接符才可以设置默认值--> <propertyname="org.apache.ibatis.parsing.PropertyParser.enable-default-value"value="true"/> </properties>
注意:在MyBatis配置文件(mybatis-config.xml)中,<properties>标签的配置必须写在<settings>标签的上面,因为MyBatis中的配置,不但有类型限制,还有顺序限制。
必须按照:<properties>、<settings>、<typeAliases>、<typeHandlers>、…顺序排放。
(3)编写数据库配置信息,并使用“${}”拼接符的默认值。
说明:
由于在db.propertie属性文件中,已经将jdbc.username和jdbc.password属性项注释掉了,然后在上面的配置信息中,给username和password配置项中的“${}”拼接符中设置默认值,这样程序在启动时,就会读取默认值。
补充:MyBatis映射——SQL占位符及传参
简介
本篇主要讲述Mybatis映射SQL通过#{}获取引入类型参数的属性值及通过@Param注解指定名称传参。
关于占位符与字符拼接:
占位符:占位符就是在某个地方占领一个位置,把它单独作为某个东西,比如这里就是把它作为 值。
#{}表示一个占位符号,通过#{}可以实现 preparedStatement 向占 位符中设置值, 自动进行 java
类型和 jdbc 类型转换。#{}可以有效防止 sql 注入。 #{}可以接 收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{} 括号中可以是 value 或其它名称。
字符拼接:字符拼接就是简单的对字符串拼接。没有特殊的其它含义。
表 示 拼 接 s q l 串 , 通 过 可 以 将 p a r a m e t e r T y p e 传 入 的 内 容 拼 接 在 s q l 中 且 不 进 行 j d b c 类 型 转 换 , 可 以 将 p a r a m e t e r T y p e 传 入 的 内 容 拼 接 在 s q l 中 且 不 进 行 j d b c 类 型 转 换 , 可 以 接 收 简 单 类 型 值 或 p o j o 属 性 值 , 如 果 p a r a m e t e r T y p e 传 输 单 个 简 单 类 型 值 , {}表示拼接 sql 串,通过可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,{}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,表示拼接sql串,通过可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}括号中只能是 value。
关于@Param:
在用注解来简化xml配置的时候(比如Mybatis的Mapper.xml映射文件中的sql参数引入);
@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中(一般通过#{}的方式,${}会有sql注入的问题)。
#{}: 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符 。 ${}: 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。
MyBatis 的真正强大在于它的映射语句
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
映射文件中有很多属性,常用的就是parameterType(输入类型)、resultType(输出类型)、resultMap()、rparameterMap()。
实例步骤
先建好实体类Teacher和接口类
Teacher类
packagecom.lanou3g.mybaties.bean; importlombok.Getter; importlombok.Setter; @Getter @Setter publicclassTeacher{ privateIntegerid; privateStringtname; privateIntegerage; privateIntegersalary; publicTeacher(){} @Override publicStringtoString(){ return"Teacher{"+ "id="+id+ ",tname='"+tname+'\''+ ",salary="+salary+ ",remark='"+remark+'\''+ ",age="+age+ '}'; } privateStringremark; publicTeacher(Integerid,Stringtname,Integerage,Integersalary,Stringremark){ this.id=id; this.tname=tname; this.age=age; this.salary=salary; this.remark=remark; } publicTeacher(Integerid){ this.id=id; } }
接口类
packagecom.lanou3g.mybaties.dao; importcom.lanou3g.mybaties.bean.Teacher; importorg.apache.ibatis.annotations.Param; importjava.util.List; publicinterfaceTeacherDao{ List<Teacher>queryAll(); TeacherqueryById(intid); TeacherqueryByIdAndAge(@Param("id")intid,@Param("age")intage); intinsertTeacher(Teacherteacher); intinsertTeacherByParam(@Param("tname")Stringtname,@Param("age")intage); intupdateTeacherById(Teacherteacher); intdeleteTeacherById(intid); }
主要还是xml配置文件的配置,下面是 mybatis_conf.xml文件,它主要引入外部的properties文件(用于配置数据源)、定义类型别名(全局)、配置多套环境的数据库连接参数及引入哪些Mapper映射文件等
mybatis_conf.xml配置文件
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEconfiguration PUBLIC"-//mybatis.org//DTDConfig3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <propertiesresource="jdbc.properties"/> <settings> <settingname="mapUnderscoreToCamelCase"value="false"/> </settings> <typeAliases> <!--这样我们就可以在mybatis的的上下文中使用Teacher来代替全路径名了,减少配置的复杂度。--> <typeAliastype="com.lanou3g.mybaties.bean.Teacher"alias="Teacher"/> <!--default属性,这个属性作用就是指定当前情况下使用哪个数据库配置, 也就是使用哪个<environment>节点的配置, default的值就是配置的<environment>标签元素的id值。--> <environmentsdefault="test"> <environmentid="test"> <!--事务管理器: MANAGED:这个配置就是告诉mybatis不要干预事务,具体行为依赖于容器本身的事务处理逻辑。 JDBC:这个配置就是直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。 --> <!--使用jdbc事务管理--> <transactionManagertype="JDBC"/> <!--数据库连接池--> <dataSourcetype="POOLED"> <propertyname="driver"value="${jdbc.driver}"/> <propertyname="url"value="${jdbc.url}"/> <propertyname="username"value="${jdbc.user}"/> <propertyname="password"value="${jdbc.password}"/> </dataSource> </environment> </environments> <!--<mappers>用来在mybatis初始化的时候,告诉mybatis需要引入哪些Mapper映射文件。--> <mappers> <!--通过class属性指定mapper接口名称,此时对应的映射文件必须与接口位于同一路径下, 并且名称相同--> <!--通过resource属性引入classpath路径的相对资源--> <mapperresource="mapper/TeacherMapper.xml"/> </mappers> </configuration>
TeacherMapper.xml映射文件
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapper PUBLIC"-//mybatis.org//DTDMapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace对应空Dao接口的全名--> <!--namespace属性 在MyBatis中,Mapper中的namespace用于绑定Dao接口的,即面向接口编程。 它的好处在于当使用了namespace之后就可以不用写接口实现类, 业务逻辑会直接通过这个绑定寻找到相对应的SQL语句进行对应的数据处理--> <mappernamespace="com.lanou3g.mybaties.dao.TeacherDao"> <!--此处的id是查询语句的名称,对应接口中的方法名--> <!--指定resultType返回值类型时Teacher类型的, Teacher在这里是一个别名,代表的是com.lanou3g.mybaties.bean.Teacher 对于引用数据类型,都是将大写字母转小写,比如HashMap对应的别名是'hashmap' 基本数据类型考虑到重复的问题,会在其前面加上'_',比如byte对应的别名是'_byte' --> <selectid="queryAll"resultType="Teacher"> <!-- 通过resultType指定查询的结果是Teacher类型的数据 只需要指定resultType的类型,MyBatis会自动将查询的结果映射成JavaBean中的属性 --> select*fromteacher; </select> <!--带一个简单类型的参数,这种情况下parameterType属性可以省略, mybatis可以自动推断出类型--> <selectid="queryById"resultType="Teacher"> select*fromteacherwhereid=#{id}; </select> <!--带两个参数,需要在接口中通过@Param注解指定名称(因为编译时参数名不会保留)--> <selectid="queryByIdAndAge"resultType="Teacher"> select*fromteacherwhereid=#{id}andage<=#{age}; </select> <!--insert、update、delete的返回值都是int(影响行数)--> <!--自定义类型参数,通过#{属性名}可以直接获取引入类型参数的属性值--> <insertid="insertTeacher"parameterType="Teacher"> insertintoteacher(tname)values(#{tname}); </insert> <insertid="insertTeacherByParam"> insertintoteacher(tname,age)values(#{tname},#{age}); </insert> <updateid="updateTeacherById"parameterType="Teacher"> updateteachersettname=#{tname},age=#{age}whereid=#{id} </update> <deleteid="deleteTeacherById"> deletefromteacherwhereid=#{id}; </delete> </mapper>
前面完成后,就要测试了。不过在测试时需要实例化创建对象,因要实现多个方法,在这先建MyBatisTools.java工具类,其主要进行封装Mybatis初始化操作,要求支持创建多env sqlSessionFactory,整个应用生命周期内相同env的sqlSessionFactory对象只有一个(这个类不要过于探究,会用即可)。
MyBatisTools.java
packagecom.lanou3g.mybaties; importlombok.extern.slf4j.Slf4j; importorg.apache.ibatis.io.Resources; importorg.apache.ibatis.session.ExecutorType; importorg.apache.ibatis.session.SqlSession; importorg.apache.ibatis.session.SqlSessionFactory; importorg.apache.ibatis.session.SqlSessionFactoryBuilder; importjava.io.InputStream; importjava.util.concurrent.ConcurrentHashMap; /** *封装Mybatis初始化操作 *支持创建多envsqlSessionFactory *整个应用生命周期内相同env的sqlSessionFactory对象只有一个 */ @Slf4j publicclassMyBatisTools{ privatestaticConcurrentHashMap<String,SqlSessionFactory>factoryMap=newMyConcurrentHashMap(); privatestaticMyBatisToolsmyBatisTools; privateMyBatisTools(){} publicstaticMyBatisToolsgetInstance(){ if(myBatisTools==null){ synchronized(MyBatisTools.class){ if(myBatisTools==null){ myBatisTools=newMyBatisTools(); } } } log.debug("当前一共有:"+factoryMap.size()+"个SqlSessionFactory实例"); log.debug("他们分别是:"+factoryMap); returnmyBatisTools; } publicSqlSessionFactorygetSessionFactory(Stringenv){ try{ //1.读入配置文件 InputStreamin=Resources.getResourceAsStream("mybatis_conf.xml"); //2.构建SqlSessionFactory(用于获取sqlSession) SqlSessionFactorysessionFactory=null; synchronized(factoryMap){ if(factoryMap.containsKey(env)){ returnfactoryMap.get(env); }else{ sessionFactory=newSqlSessionFactoryBuilder().build(in,env); factoryMap.put(env,sessionFactory); } } returnsessionFactory; }catch(Exceptione){ log.error("初始化SqlSessionFactory失败",e); returnnull; } } publicSqlSessionopenSession(){ returngetSessionFactory(null).openSession(); } publicSqlSessionopenSession(booleanautoCommit){ returngetSessionFactory(null).openSession(autoCommit); } publicSqlSessionopenSession(ExecutorTypeexecutorType,booleanautoCommit){ returngetSessionFactory(null).openSession(executorType,autoCommit); } } /** *继承原生ConcurrentHashMap,处理nullkey问题 */ classMyConcurrentHashMapextendsConcurrentHashMap{ @Override publicObjectput(Objectkey,Objectvalue){ if(key==null){ key="null"; } returnsuper.put(key,value); } @Override publicbooleancontainsKey(Objectkey){ if(key==null){ key="null"; } returnsuper.containsKey(key); } @Override publicObjectget(Objectkey){ if(key==null){ key="null"; } returnsuper.get(key); } }
最后就是测试,在AppTest类测试
AppTest
@Slf4j publicclassAppTest { /** *RigorousTest:-) */ TeacherDaoteacherDao=null; @Before publicvoidsetUp(){ teacherDao=MyBatisTools.getInstance().openSession(true).getMapper(TeacherDao.class); } /** *练习查询多个库(用到了多环境配置) */ @Test publicvoidtextqueryById(){ Teacherteacher=teacherDao.queryById(1); System.out.println(teacher); } @Test publicvoidtext(){ List<Teacher>teachers=teacherDao.queryAll(); System.out.println(teachers); } /** *多个参数查询语句 */ @Test publicvoidtestQueryByIdAndAge(){ TeacherteacherList=teacherDao.queryByIdAndAge(1,65); log.info("查询结果:"+teacherList); } @Test publicvoidtestInsert(){ //新增Teacher表 System.out.println("--------------插入前:"); List<Teacher>teacherList=teacherDao.queryAll(); System.out.println(teacherList); intret=teacherDao.insertTeacher(newTeacher("好人")); log.info("影响的行数:"+ret); //比较low的写法(不推荐) //intret=teacherDao.insertTeacherByParam("哈哈哥",99); //log.info("影响的行数:"+ret); System.out.println("--------------插入后:"); teacherList=teacherDao.queryAll(); System.out.println(teacherList); } @Test publicvoidtestUpdate(){ Teacherteacher=newTeacher(); teacher.setId(6); teacher.setAge(99); teacher.setTname("乔巴老师"); introws=teacherDao.updateTeacherById(teacher); log.info("更新行数:"+rows); } @Test publicvoidtestDelete(){ introws=teacherDao.deleteTeacherById(13); log.info("删除行数:"+rows); } @Test publicvoidtestinsertTeacherByParam(){ introw=teacherDao.insertTeacherByParam("hh",22); System.out.println(row); } }
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注恰卡编程网行业资讯频道,感谢您对恰卡编程网的支持。
推荐阅读
-
Mybatis中怎么利用useGeneratedKeys获取自增主键
Mybatis中怎么利用useGeneratedKeys获取自增主键,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以...
-
Mybatis中怎么实现SQL防注入
这篇文章给大家介绍Mybatis中怎么实现SQL防注入,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。什么是S...
-
mybatis中怎么利用注解对对象进行批量更改
这期内容当中小编将会给大家带来有关mybatis中怎么利用注解对对象进行批量更改,文章内容丰富且以专业的角度为大家分析和叙述,阅读...
-
mybatis(如何判断list集合是否包含指定数据)
mybatis,如何判断list集合是否包含指定数据需求1、在mybatis脚本中想要判断list中是否含有某个字符串。2、动...
-
Mybatis如何自动生成数据库表的实体类
-
Mybatis中多个对象包含同一个对象的处理操作
-
mybatis配置对象包含对象以及List的方式
mybatis配置对象包含对象以及List的方式mybatis配置对象包含对象及List这里隐藏getset方法publ...
-
Mybatis中resultMap如何使用
-
如何使用mybatis查询语句
本篇文章给大家分享的是有关如何使用mybatis查询语句,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收...
-
解决mybatis中的mapper命名问题
mybatismapper命名问题mapper文件中id命名最好首字母小写,避免让mybatis认为是一个类<...