前面聊了一些配置文件的标签意义,在实例演示的时候,发现用的sql都是定死的,也就是无法传递参数,这个不符合开发的环境的,毕竟程序是需要交互的,自然也会有参数传递,下面依次进行演示。
在映射文件中参数两种写法
前面实例可以看出mybatis其没有实现接口的类,而是通过配置映射文件进行实现,当然框架是通过反射解读XML而实现,所以如何在XML中实现参数呢?有两种写法。${}和#{}
- ${} :本质就是字符串拼接,拼接一个sql语句。如果是字符串,日期等需要添加单引号了。
- #{}:本质是一个占位符,然后进行赋值。然后会自动将为参数两侧添加单引号。
还是先说理论,然后进行演示就明白其区别,或者说用发。
因为为了观察一下其运行是否带有单引号,所以需要用log4j这种第三方日志包更方便一些,所以通过maven的pom.xml添加包环境:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
然后再添加一个log4j.properties文件
内容如下:
#日志输出到哪里
log4j.rootLogger=ALL,systemOut
# 日志输出到控制台
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout
log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/ddHH:mm:ssS}][%l]%n%m%n
log4j.appender.systemOut.Threshold = DEBUG
log4j.appender.systemOut.ImmediateFlush = TRUE
log4j.appender.systemOut.Target = System.out
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
然后映射配置文件中如下些:
<?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.xzd.mapper.StudentMapper">
<!-- 这个配置文件id和 mapper类中的方法一样-->
<select id="getStudentByName" resultType="com.xzd.domain.Student">
<!-- 配置两个进演示 -->
SELECT * FROM testmybatis.student WHERE SNAME=#{sname}
<!-- SELECT * FROM testmybatis.student WHERE SNAME=${sname} -->
</select>
</mapper>
映射的接口:
package com.xzd.mapper;
import com.xzd.domain.Student;
public interface StudentMapper {
Student getStudentByName(String sname);
}
Student这个对象类就不粘贴全部了,看图
核心配置文件:
<?xml version="1.0" encoding="utf-8"?>
<!--配置文件中可以使用哪些标签,这个地方是配置这是一个mybatis文件,使用mybatis文件标签-->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--开始配置信息-->
<configuration>
<properties resource="jdbc.properties"></properties>
<!-- 是否配置日志 log4j-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 是否因为jdbc等外部配置文件-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.xzd.mapper" ></package>
</mappers>
</configuration>
测试类:
public class Test_mabtis {
@Test
public void test1() throws IOException {
// 通过IO操作配置文件 所以说这个配置文件可以改名字,一般默认是mybatis-config.xml
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSession类似与jdb中connection,但是其通过SqlSession工厂而创建的,而这个工厂却是通过工厂的构造类SqlSessionFactoryBuilder得到工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 返回SqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 这个通过代理模式,传入什么类返回什么类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
System.out.println("#{}-------- "+result);
// System.out.println("${}-------- "+result);
// 关闭sqlSession
sqlSession.close();
}
}
- 首先打印使用#{}打印日志截图:
-
首先打印使用${}打印日志截图:
因为了演示不会自动添加单引号,故意用名字作为查询字段,所以会直接报错:
如果修改如下:
<select id="getStudentByName" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME='${sname}'
</select>
可以看出没有问题了,而且也可以看出其直接是一个拼接好的sql语句。
一个参数
mybatis 3.5之前版本
其实上面的例子,已经演示了一个参数,但是为什么现在又要说一下单个参数呢?
现在将映射文件修改为:
<select id="getStudentByName" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME='${value}'
</select>
其它的不修改,可以看出传递的参数名为sname,但是我使用value,看一下结果:
似乎可以随意写参数名字,那如下测试呢?
<select id="getStudentByName" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME='${abc}'
</select>
报错了,那么使用**#{}**呢?
<select id="getStudentByName" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME=#{abc}
</select>
这个却可以,然后#{value}也是上面结果,所以可以总结:
如果是一个参数,在映射文件中无论使用#{}。其中参数的名字,可以所以写都不会影响结果。比如实例中的使用value,也可以使用abc等等。 但是如果使用${}的话,只能使用类属性或者value
mybatis 3.5之后版本
这个就不一样了,#{}几乎一样,但是${}就一样了,如下演示:
<select id="getStudentByName" resultType="com.xzd.domain.Student">
<!-- 估计两边不带有单引号,因为还有一点就是报错通过log4j输出的日志信息也不同 -->
SELECT * FROM testmybatis.student WHERE SNAME=${abc}
</select>
可以看出如果在3.5版本之后,总结:
如果是一个参数的话,无论使用#{}或者${} 其中对参数可以任何字符代替比如使用类属性,value,甚至是abc等
两个以及以上参数
当然这个不同版本的效果也是不同,所以就以3.5之后的版本进行演示,然后说一下之前版本的一些不同,毕竟很多开发环境也是随着版本迭代而变化的。
mybatis3.5之后版本
现在进行如下尝试,首先根据一个参数的经验如此
接口类:
// 添加一个需要通过名字和Id查询的方法,当然一般id足以查询某条数据了,但是本篇主要聊参数如何传递,所以大家先忽略这些问题
Student getStudentIdNAme(String sname,int id);
配置映射文件,添加:
<select id="getStudentIdNAme" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME=#{sname} and SID= #{sid}
</select>
然后调用测试类,可以看下如下报错信息:
直接告诉如何在映射文件中写参数了
然后如下尝试:
<select id="getStudentIdNAme" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME=#{arg0} and SID= #{arg1}
</select>
然后这样修改:
<select id="getStudentIdNAme" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME=#{ param1} and SID= #{ param2}
</select>
可以看出如果是通过arg开头是从0开始的,但是如果通过param开头是从1开始的。
为什么会这样,其实,mybatis在传递参数的时候,会将数据放在map中,其中一个情况是通过arg…为key,参数为值。第二种情况是以param…为key,然后参数为值。所以可以通过两个key获取相对应的值了。
在3.5版本之后,无论#{}还是 都可以通过上面规则得到结果。只不过 {}都可以通过上面规则得到结果。只不过 都可以通过上面规则得到结果。只不过{}需要添加单引号才行。
mybatis 3.5之前版本
这个又分两种情况,比如3.4.6版本和3.5版本没有什么区别,但是比如3.4.0版本的话,可以看其输出的错误信息:
可以直接通过数字来得到信息。但是这个数字只能使用在#{}中,如果使用在${}中,数字会直接变成条件值数字,而不是数字所代表的参数值,如下:
所以注意一下。在不同的版本的中的使用情况。
补充 如果传递的是map
上面说到mybatis会将多个传递参数变成一个map,那么直接传递一个参数map,然后进行调用如何?
现在进行演示:
import com.xzd.domain.Student;
import java.util.Map;
public interface StudentMapper {
Student getStudentByMap(Map<String,Object> map);
}
然后再映射文件中添加:
<select id="getStudentByMap" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME='${sname}' and SID= '${sid}'
</select>
然后再调用测试中如下:
public class Test_mabtis {
@Test
public void test1() throws IOException {
// 通过IO操作配置文件 所以说这个配置文件可以改名字,一般默认是mybatis-config.xml
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSession类似与jdb中connection,但是其通过SqlSession工厂而创建的,而这个工厂却是通过工厂的构造类SqlSessionFactoryBuilder得到工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 返回SqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 这个通过代理模式,传入什么类返回什么类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Map<String, Object> map=new HashMap<>();
map.put("sname","张三");
map.put("sid",1);
Student result=studentMapper.getStudentByMap(map);
System.out.println(" -------- "+result);
sqlSession.close();
}
}
看结果,没有问题。
可以看出也可以通过自定义一个map,进行传递,参数之间可以使用自己定义map的key。但是无法使用arg或者parm,因为会取不到值。
实验:
<select id="getStudentByMap" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME='${arg0}' and SID= '${arg1}'
</select>
补充传递的是一个对象
前面既然可以传递一个map,开发过程中也会传递一个对象,如果传递的是对象呢?现在试一下。
不过一般传递对象的时候是插入操作。可以如下
<insert id="insertOne" >
INSERT INTO `testmybatis`.`student` (`sid`, `sname`, `sage`, `ssex`)
VALUES ('${sid}', '${sname}', '${sage}', '${ssex}');
</insert>
映射类:
public interface StudentMapper {
void insertOne(Student student);
}
测试类:
public class Test_mabtis {
@Test
public void test1() throws IOException {
// 通过IO操作配置文件 所以说这个配置文件可以改名字,一般默认是mybatis-config.xml
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSession类似与jdb中connection,但是其通过SqlSession工厂而创建的,而这个工厂却是通过工厂的构造类SqlSessionFactoryBuilder得到工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 返回SqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 这个通过代理模式,传入什么类返回什么类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student=new Student(4,"宫崎",18,"男");
studentMapper.insertOne(student);
sqlSession.close();
}
}
成功插入数据库中,可以查询数据库。
通过注解传递参数
还有一种方式,那就是通过注解传递,而这个注解才是开发过程中常用的一种方式:
@Param([value=]"重命名参数")
还是老规矩,来演示:
<select id="getStudentIdNAme" resultType="com.xzd.domain.Student">
<!-- 注解中故意写错,看如何报错 -->
SELECT * FROM testmybatis.student WHERE SNAME=#{abc} and SID= #{sid}
</select>
在映射配置类中使用注解:
public interface StudentMapper {
// 这事在形参前面使用@Param注解
Student getStudentIdNAme(@Param("sname") String sname, @Param("sid") int sid);
}
测试类调用:
public class Test_mabtis {
@Test
public void test1() throws IOException {
// 通过IO操作配置文件 所以说这个配置文件可以改名字,一般默认是mybatis-config.xml
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSession类似与jdb中connection,但是其通过SqlSession工厂而创建的,而这个工厂却是通过工厂的构造类SqlSessionFactoryBuilder得到工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 返回SqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 这个通过代理模式,传入什么类返回什么类
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student result = studentMapper.getStudentIdNAme("张三",1);
sqlSession.close();
}
}
因为前面说了在注解中故意写错,看报错的的信息,所以得到报错信息如下:
可以看出,在映射文件中得到传递的参数值,可以通过@Param中修改的参数名得到,也可以通过param1这样得到,但是无法通过arg0这样得到了。
<select id="getStudentIdNAme" resultType="com.xzd.domain.Student">
<!-- 注解中故意写错,看如何报错 -->
SELECT * FROM testmybatis.student WHERE SNAME=#{sname} and SID= #{sid}
</select>
或者
<select id="getStudentIdNAme" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME='${param1}' and SID= '${param1}'
</select>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SvSSJyvs-1673871550840)(F:\文档\笔记\java\MyBatis\3:mybatis传递参数.assets\image-20230116201659766.png)]
但是如下:
<select id="getStudentIdNAme" resultType="com.xzd.domain.Student">
SELECT * FROM testmybatis.student WHERE SNAME='${arg0}' and SID= '${arg1}'
</select>
就会出现报错。