MyBatis中#{}占位符与${}拼接符的用法说明
1、关于#{}占位符
先来看以下的示例,该示例是MyBatis中的SQL映射配置文件(Mapper配置文件),在该配置中使用了#{}占位符。
SELECT*FROMtb_userWHEREid=#{id} INSERTINTOtb_user(user_name,blog_url,remark) VALUES(#{userName},#{blogUrl},#{remark});
在SQL映射配置文章中,输入参数需要用占位符来标识对应的位置。
在传统的JDBC编程中,占位符用“?”来标识,然后在加载SQL之前按照“?”的位置设置参数。
而“#{}”在MyBatis中也代表一种占位符,该符号接受输入参数,在大括号中编写参数名称来接受对应参数。
“#{}”接受的输入参数的类型可以是简单类型、普通JavaBean或者HashMap。
当接受简单类型时,“#{}”中可以写“value”或者其他任意名称。
如果接受的是JavaBean,它会通过OGNL读取对象中的属性值。
2、关于${}拼接符
再来看以下的示例,该示例是MyBatis中的SQL映射配置文件(Mapper配置文件),在该配置中使用了${}拼接符。
SELECT*FROMtb_userWHEREuser_nameLIKE'%${value}%'
在SQL映射配置文件中,有时候需要拼接SQL语句。例如在模糊查询的时候,就需要在查询条件的两侧拼接两个“%”字符串,这个时候如果使用“#{}”占位符是不行的。在MyBatis中,“${}”在SQL配置文件中代表一个“拼接符号”,可以在原有SQL语句上拼接新的符合SQL语法的语句。
但是要注意的是,使用“${}”拼接的SQL语句,会引起SQL注入,所以一般不建议使用“${}”。
“${}”接受输入参数的类型可以是简单类型、普通JavaBean或者HashMap。
当接受简单类型时,“${}”中只能写“value”,而不能写其他任意名称。
如果接受的是JavaBean,它会通过OGNL读取对象中的属性值。
另外,在MyBatis3.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)中,使用
注意:在MyBatis配置文件(mybatis-config.xml)中,
必须按照:
(3)编写数据库配置信息,并使用“${}”拼接符的默认值。
说明:
由于在db.propertie属性文件中,已经将jdbc.username和jdbc.password属性项注释掉了,然后在上面的配置信息中,给username和password配置项中的“${}”拼接符中设置默认值,这样程序在启动时,就会读取默认值。
补充:MyBatis映射——SQL占位符及传参
简介
本篇主要讲述Mybatis映射SQL通过#{}获取引入类型参数的属性值及通过@Param注解指定名称传参。
关于占位符与字符拼接:
占位符:占位符就是在某个地方占领一个位置,把它单独作为某个东西,比如这里就是把它作为值。
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java
类型和jdbc类型转换。#{}可以有效防止sql注入。#{}可以接收简单类型值或pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
字符拼接:字符拼接就是简单的对字符串拼接。没有特殊的其它含义。
表示拼接sql串,通过可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换,可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}表示拼接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预编译语句(preparedstatement)的参数标记符,一个#{}被解析为一个参数占位符。${}:仅仅为一个纯碎的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{ ListqueryAll(); 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配置文件
TeacherMapper.xml映射文件
select*fromteacher; select*fromteacherwhereid=#{id}; select*fromteacherwhereid=#{id}andage<=#{age}; insertintoteacher(tname)values(#{tname}); insertintoteacher(tname,age)values(#{tname},#{age}); updateteachersettname=#{tname},age=#{age}whereid=#{id} deletefromteacherwhereid=#{id};
前面完成后,就要测试了。不过在测试时需要实例化创建对象,因要实现多个方法,在这先建MyBatisTools.java工具类,其主要进行封装Mybatis初始化操作,要求支持创建多envsqlSessionFactory,整个应用生命周期内相同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{ privatestaticConcurrentHashMapfactoryMap=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(){ Listteachers=teacherDao.queryAll(); System.out.println(teachers); } /** *多个参数查询语句 */ @Test publicvoidtestQueryByIdAndAge(){ TeacherteacherList=teacherDao.queryByIdAndAge(1,65); log.info("查询结果:"+teacherList); } @Test publicvoidtestInsert(){ //新增Teacher表 System.out.println("--------------插入前:"); List 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); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。