Mybatis是ORM持久层框架的佼佼者,它封装了JDBC,真正实现了SQL语句与Java代码的分离,它优秀的功能为:支持动态SQL,缓存,物理分页插件PageHelper。注意本篇介绍以数组为传递参数进行数据的查询 它在实际运用中有两个例子:1、SQL语句中使用IN的情况,可以使用数组封装IN中的值;2、批量操作数据的情况,可以把操作的数据封装在数组中。
第一步:新建一个Maven项目mybatis_parameter
(不使用模板),其中pom.xml配置信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.envy</groupId> <artifactId>mybatis_parameter</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!--pageHelper分页插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.6</version> </dependency> </dependencies> </project>
第二步:创建数据库mybatis_parameter
和表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 drop table if exists person; create table person( id int PRIMARY key auto_increment, username varchar(20), email varchar(20), gender varchar(20), department_id int ); drop table if exists department; create table department( id int primary key auto_increment, department_name varchar(50) ); alter table person add constraint fk_person_department foreign key(department_id) references department(id);
第三步:配置db.properties
和mybatis-config.xml
、logj.properties
文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 *******************************db.properties***************************************** jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis_parameter?useUnicode=true&characterEncoding=UTF-8 jdbc.username=root jdbc.password=root *******************************logj.properties***************************************** log4j.rootLogger=DEBUG, A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n *******************************mybatis-config.xml***************************************** <?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> <!-- properties配置,用于加载外部的properties配置文件 --> <properties resource="db.properties"></properties> <!-- 配置配置项 --> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="jdbcTypeForNull" value="NULL"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings> <!--别名--> <typeAliases> <package name="com.envy.bean"/> </typeAliases> <!--配置数据源--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"></transactionManager> <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主要用于配置我们外部的映射配置文件,在主配置文件中需要引入加载映射配置文件 --> <mappers> <!-- mapper主要配置引入某一个具体的mapper映射文件,通常是在resource文件下以路径方式进行引入 --> <mapper resource="mapper/PersonMapper.xml"/> </mappers> </configuration>
第四步:新建com.envy.dao
、com.envy.bean
、com.envy.test
、com.envy.interceptor
包 ,接着在bean中新建两个Bean类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 *******************************Person.java***************************************** package com.envy.bean; public class Person { private Integer id; private String username; private String email; private String gender; private Integer departmentId; private Department department; public Person(){} public Integer getDepartmentId() { return departmentId; } public void setDepartmentId(Integer departmentId) { this.departmentId = departmentId; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } } *******************************Department.java***************************************** package com.envy.bean; import java.util.List; public class Department { private Integer id; private String departmentName; private List<Person> personList; public Department(){} public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getDepartmentName() { return departmentName; } public void setDepartmentName(String departmentName) { this.departmentName = departmentName; } public List<Person> getPersonList() { return personList; } public void setPersonList(List<Person> personList) { this.personList = personList; } }
第五步:在dao包中新建一个接口PersonMapper.java,接着在resource包中新建一个mapper包然后在mapper包中新建PersonMapper.xml文件。
完成了准备工作后开始进行介绍mybatis中的参数传递等知识。
Mybatis参数传递介绍 注意本篇介绍以数组为传递参数进行数据的查询。 mybatis对于参数处理有三种情况:1、传递单个参数的形式,mybatis会自动进行参数的赋值;2、传递多个参数的形式,mybatis会自动封装在Map集合中;3、传递Collection、List、Array等参数的形式,mybatis会根据一定的规则封装在Map集合中。
Mybatis核心的API操作流程如下图所示:
传递单个参数 传递单个参数时,mybatis会直接取出参数值给mapper文件赋值,如id=#{id}
。
接口PersonMapper.java
代码如下:
1 2 3 4 5 package com.envy.dao; public interface PersonMapper { void deletePerson (Integer id); }
PersonMapper.xml
文件中的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?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.envy.dao.PersonMapper"> <resultMap id="BaseResultMap" type="com.envy.bean.Person"> <id column="id" property="id" javaType="Integer"/> <result property="username" column="username" javaType="String"/> <result property="email" column="email" javaType="String"/> <result property="gender" column="gender" javaType="String"/> <result property="departmentId" column="department_id" javaType="Integer"/> <result property="username" column="username" javaType="String"/> <!--属性关联,这里使用department_id来获取department信息,使用select属性来调用之前DepartmentDao中定义的sql方法--> <association property="department" column="department_id" javaType="Department" select="com.envy.dao.DepartmentMapper.searchById"/> </resultMap> <delete id="deletePerson" parameterType="Integer"> delete from person where id =#{id} </delete> </mapper>
从前面的图中可以看出Mybatis需要先使用SqlSessionFactoryBuilder
的build
方法来构造SqlSessionFactory
对象,SqlSessionFactory
对象其实就相当于数据库,因此最好是使用单例模式来创建该对象。mybatis_parameter\src\main\java\com\envy\test\ParameterTest.java
文件中新建getSqlSessionFactory
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static SqlSessionFactory sqlSessionFactory=null; public static SqlSessionFactory getSqlSessionFactory(){ if(sqlSessionFactory==null){ String resource = "mybatis-config.xml"; try { InputStream is = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { e.printStackTrace(); } } return sqlSessionFactory; }
接着新建一个deletePerson
方法来调用它,并执行相应的方法:
1 2 3 4 5 6 7 8 9 @Test public void deletePerson(){ //SqlSessionFactory相当于数据库,SqlSession相当于一次连接 SqlSession sqlSession = getSqlSessionFactory().openSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); personMapper.deletePerson(6); //mybatis的事务不会自动提交,因此需要借助于SqlSession的commit方法去提交事务 sqlSession.commit(); }
运行该方法,发现数据库已经成功的将id为6的Person对象给删除了。注意以下代码:
1 2 3 <delete id="deletePerson" parameterType="Integer"> delete from person where id =#{id} </delete>
这个id =#{id}
中前者id是数据库中的属性,后者id是deletePerson方法的形参,不是实参,因此修改为其他的名字,该代码也是可以正常运行的。
传递多个参数 先按照之前传递单个参数的想法来试试(多个参数之间用逗号隔开),看看能不能运行成功。
接口PersonMapper.java
新增代码如下:
1 Person selectByUserNameAndGender(String username,String gender);
PersonMapper.xml
文件中新增代码如下:
1 2 3 <select id="selectByUserNameAndGender" resultType="Person"> select * from person where username=#{username} and gender = #{gender} </select>
ParameterTest.java
文件新增selectByUserNameAndGender
方法:
1 2 3 4 5 6 7 8 @Test public void selectByUserNameAndGender(){ //SqlSessionFactory相当于数据库,SqlSession相当于一次连接 SqlSession sqlSession = getSqlSessionFactory().openSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); Person person = personMapper.selectByUserNameAndGender("jack","男"); System.out.println(person); }
运行结果如下:
1 Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
意思就是说mybatis中没有找到你定义的username参数,只有四个参数:[arg1, arg0, param1, param2]
,那尝试将其修改为这些参数(注意此处为查询操作,因此需要在实体类中新增toString方法,否则会造成阅读障碍):
1 2 3 <select id="selectByUserNameAndGender" resultType="Person"> select * from person where username=#{param1} and gender=#{param2} </select>
运行结果:
1 Person{id=1, username='jack', email='jack@qq.com', gender='男', departmentId=1, department=null}
第一种:JavaBean传递参数,其实也就是封装POJO类。前提是多个参数是业务逻辑的数据模型,可以直接传入POJO,在xml文件中使用#{属性名}
取出传入POJO的属性值。
PersonMapper.java
文件中的selectByUserNameAndGender
方法修改为:
1 2 //封装成POJO对象 Person selectByUserNameAndGender(Person person);
PersonMapper.xml
文件中新增代码如下:
1 2 3 4 <!--封装成POJO对象--> <select id="selectByUserNameAndGender" resultType="Person"> select * from person where username=#{username} and gender=#{gender} </select>
ParameterTest.java
文件中的selectByUserNameAndGender
方法修改为(注意需要去Person实体类中创建只含有username和gender参数的构造方法):
1 2 3 4 5 6 7 8 9 10 //第一种封装成POJO对象 @Test public void selectByUserNameAndGender(){ //SqlSessionFactory相当于数据库,SqlSession相当于一次连接 SqlSession sqlSession = getSqlSessionFactory().openSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); Person person = personMapper.selectByUserNameAndGender(new Person("jack","男")); System.out.println(person); sqlSession.commit(); }
运行结果如下:
1 Person{id=1, username='jack', email='jack@qq.com', gender='男', departmentId=1, department=null}
第二种:Map处理。前提是参数的个数比较少,且没有对应的JavaBean,那么可以封装成Map对象。在xml文件中使用#{key}
取出map中所对应的值。
PersonMapper.java
文件中的selectByUserNameAndGender
方法修改为:
1 2 //封装成Map Person selectByUserNameAndGender(Map<String,Object> param);
PersonMapper.xml
文件中新增代码如下:
1 2 3 4 <!--第二种:封装成Map对象--> <select id="selectByUserNameAndGender" resultType="Person"> select * from person where username=#{name} and gender=#{gender} </select>
ParameterTest.java
文件中的selectByUserNameAndGender
方法修改为(注意此时map的key值可以不和数据库中字段的属性值一一对应,但是xml文件中的#{key}
必须是和map中的key是一致的):
1 2 3 4 5 6 7 8 9 10 11 12 //第二种封装成Map对象 @Test public void selectByUserNameAndGender(){ //SqlSessionFactory相当于数据库,SqlSession相当于一次连接 SqlSession sqlSession = getSqlSessionFactory().openSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); Map<String,Object> param = new HashMap<String, Object>(); param.put("name","bob"); param.put("gender","男"); Person person = personMapper.selectByUserNameAndGender(param); System.out.println(person); }
运行结果如下:
1 Person{id=2, username='bob', email='bob@qq.com', gender='男', departmentId=1, department=null}
第三种:注解@Param
。由于以上两种方式都需要手动创建Map及对象,不够简洁,可以使用@Param
注解,它可以很明确的指定封装参数时map的key。
PersonMapper.java
文件中的selectByUserNameAndGender
方法修改为:
1 2 //使用Param注解 Person selectByUserNameAndGender(@Param("UserName")String username,@Param("Gender")String gender);
PersonMapper.xml
文件中新增代码如下(注意此处username=#{UserName}
中的UserName
必须是前面@Param
注解中使用到的,通常情况下该名称和参数名称保持一致,如此处最好是username,但是为了更清楚的认识,这里就设置不同):
1 2 3 4 <!--第三种:使用Param注解--> <select id="selectByUserNameAndGender" resultType="Person"> select * from person where username=#{UserName} and gender=#{Gender} </select>
ParameterTest.java
文件中的selectByUserNameAndGender
方法修改为:
1 2 3 4 5 6 7 8 9 //第三种使用@Param注解 @Test public void selectByUserNameAndGender(){ //SqlSessionFactory相当于数据库,SqlSession相当于一次连接 SqlSession sqlSession = getSqlSessionFactory().openSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); Person person = personMapper.selectByUserNameAndGender("marry","女"); System.out.println(person); }
运行结果如下:
1 Person{id=3, username='marry', email='marry@qq.com', gender='女', departmentId=2, department=null}
有些人比较粗心,第一个参数前使用了注解,第二个参数前没有,那么在xml文件中,第一个还是可以使用注解中的值,但是第二个就必须使用前面四个中的某一个[arg0,arg1, param1, param2]
,至于具体哪一个则需要判断了。
传递Collection、List、Array等参数 传递Collection、List、Array等参数时式,mybatis会根据一定的规则 封装在Map集合中。其实针对不同的参数,mybatis提供了不同的方式。
当参数类型为Collection接口时,转换为Map,Map的key为collection(mybatis版本3.3之后);当参数类型为List接口时,除collection的值外,还可以使用list作为key(mybatis版本3.2之前含);当参数类型为数组时,转换为Map,Map的key为array。
在PersonMapper.java
文件中新增getPersonByCollection
方法:
1 Person getPersonByCollection(Collection list);
PersonMapper.xml
文件中新增代码如下(注意此处的#{collection[0]}
也可以修改为#{list[0]}
其实就是取的第一个元素):
1 2 3 <select id="getPersonByCollection" resultType="Person"> select * from person where id = #{collection[0]} </select>
在ParameterTest.java
文件中新增getPersonByCollection
方法:
1 2 3 4 5 6 7 8 @Test public void getPersonByCollection(){ //SqlSessionFactory相当于数据库,SqlSession相当于一次连接 SqlSession sqlSession = getSqlSessionFactory().openSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); Person person = personMapper.getPersonByCollection(Arrays.asList(1,2,3)); System.out.println(person); }
运行结果如下:
1 Person{id=1, username='jack', email='jack@qq.com', gender='男', departmentId=1, department=null}
上面演示的就是第一和第二种情况,接下来是第三种参数是数组的情况: 修改PersonMapper.java
文件中的getPersonByCollection
方法为:
1 Person getPersonByCollection(int[] ids);
修改PersonMapper.xml
文件中id="getPersonByCollection"
的select选项为:
1 2 3 <select id="getPersonByCollection" resultType="Person"> select * from person where id = #{array[0]} </select>
修改ParameterTest.java
文件中的getPersonByCollection
方法为:
1 2 3 4 5 6 7 8 @Test public void getPersonByCollection(){ //SqlSessionFactory相当于数据库,SqlSession相当于一次连接 SqlSession sqlSession = getSqlSessionFactory().openSession(); PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); Person person = personMapper.getPersonByCollection(new int[]{1,2,3}); System.out.println(person); }
运行结果如下:
1 Person{id=1, username='jack', email='jack@qq.com', gender='男', departmentId=1, department=null}
其实还可以通过@Param
注解来完成参数为集合类型的传递,这样就不需要考虑是用collection/array/list了,根据注解来即可,相应的步骤如下:
1、修改PersonMapper.java
文件中的getPersonByCollection
方法为:
1 Person getPersonByCollection(@Param("test")int[] ids);
修改PersonMapper.xml
文件中id="getPersonByCollection"
的select选项为:
1 2 3 <select id="getPersonByCollection" resultType="Person"> select * from person where id = #{test[0]} </select>
运行发现结果和之前的一致。
入参总结 接下来简单总结一下mybatis的入参处理:1、使用map传递参数时,会造成业务的可读性大大的降低;2、使用@Param
注解处理受到参数个数(n)的影响,当n<5
时建议使用@Param
注解;当n>=5时考虑使用JavaBean方法传递。
mybatis中的动态SQL mybatis支持动态SQL,使用foreach元素对数组、List、Set等进行循环遍历。一般用在数据库中字典相关内容的查找。foreach常用配置如下:1、collection属性的值有三个分别是list、array和map,分别对应的参数类型为:List、数组、map集合;2、item表示在迭代过程中每一个元素的别名;3、index表示在迭代过程中每次迭代到的位置(也就是下标,从零开始,map是其key);4、open是指前缀;5、close是指后缀;6、separator是分隔符表示迭代时每个元素之间以什么分隔。
注意select标签是先使用foreach元素对传进来的对象进行遍历以后,再与之前的sql语句进行拼接,最后再执行完整的sql语句。
举个例子,现在有一个int[] ids={1,2,3,4}
现在遍历它的方式如下:
1 2 3 4 5 6 <select id="getListPersonByIds" resultType="Person"> select * from person where id in <foreach collection="array" item="id" index="i" open="(" close=")" separator=","> #{id} </foreach> </select>
这个代码最后就变成了SQL语句select * from person where id in (1,2,3,4);
。
总结一下在mybatis中以数组形式进行参数传递时,需要在Mapper文件中使用foreach元素对其进行遍历以后拼接成SQL,才会执行SQL。