mybatis是持久层框架,使用mybatis可以把sql与Java代码相分离,把代码的编写在配置文件中,此处实现一个简单的实例,即用户的增删改查
1.首先需要导入jar包,mybatis的jar包导入一个核心jar包即可,因为要操作数据库,我使用的是MySQL,所以还需要导入MySQL的驱动包,jar包的截图如下所示:
2.编写实体类文件以及对应的映射文件,文件代码如下所示 :
1 package com.gp.dao; 2 3 public class User { 4 private Integer id; 5 private String name; 6 private String password; 7 8 @Override 9 public String toString() { 10 return "User [id=" + id + ", name=" + name + ", password=" + password 11 + "]"; 12 } 13 14 public Integer getId() { 15 return id; 16 } 17 18 public void setId(Integer id) { 19 this.id = id; 20 } 21 22 public String getName() { 23 return name; 24 } 25 26 public void setName(String name) { 27 this.name = name; 28 } 29 30 public String getPassword() { 31 return password; 32 } 33 34 public void setPassword(String password) { 35 this.password = password; 36 } 37 }
与其对应的配置的配置文件如下:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.gp.dao.UserMapper"> 6 <select id="selectUser" resultType="com.gp.dao.User"> 7 select * from user where id =#{id} 8 </select> 9 <insert id="insertUser"> 10 insert into user(id,name,password) values(#{id},#{name},#{password}) 11 </insert> 12 <!-- parameterType参数可以省略,也可以写上 -限制全类名 --> 13 <update id="updateUser" parameterType="com.gp.dao.User"> 14 update user set name=#{name} ,password=#{password} where id=#{id} 15 </update> 16 <delete id="delete"> 17 delete from user where id=#{id} 18 </delete> 19 </mapper>
3.编写测试文件,文件代码如下所示:
1 package com.gp.test; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 import org.apache.ibatis.io.Resources; 7 import org.apache.ibatis.session.SqlSession; 8 import org.apache.ibatis.session.SqlSessionFactory; 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 10 11 import com.gp.dao.User; 12 13 public class TestUser { 14 15 //编写获取SqlSessionFactory的静态方法 16 public static SqlSessionFactory getSqlSessionFactory() { 17 String resource = "mybatis-config.xml"; 18 InputStream inputStream; 19 try { 20 inputStream = Resources.getResourceAsStream(resource); 21 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() 22 .build(inputStream); 23 return sqlSessionFactory; 24 } catch (IOException e) { 25 e.printStackTrace(); 26 } 27 return null; 28 } 29 30 //实现查询方法 31 public void selectUser() { 32 SqlSession session = getSqlSessionFactory().openSession(); 33 try { 34 User user = session.selectOne("com.gp.dao.UserMapper.selectUser", 1); 35 System.out.println(user); 36 } finally { 37 session.close(); 38 } 39 } 40 41 //实现插入方法 42 public void insertUser(){ 43 //获取的sqlSession不会 自动提交 44 SqlSession session=getSqlSessionFactory().openSession(); 45 try{ 46 User user=new User(); 47 user.setId(6); 48 user.setName("小明"); 49 user.setPassword("123456"); 50 Object obj=session.insert("com.gp.dao.UserMapper.insertUser", user); 51 //执行完插入后一定要手动提交 52 session.commit(); 53 System.out.println(obj); 54 }finally{ 55 session.close(); 56 } 57 } 58 59 //实现修改方法 60 public void updateUser(){ 61 SqlSession session=getSqlSessionFactory().openSession(); 62 try{ 63 User user=new User(); 64 user.setId(6); 65 user.setName("小明"); 66 user.setPassword("666666"); 67 Object obj=session.insert("com.gp.dao.UserMapper.updateUser", user); 68 //执行完修改后一定要手动提交 69 session.commit(); 70 System.out.println(obj); 71 }finally{ 72 session.close(); 73 } 74 } 75 //实现删除方法 76 public void deleteUser(){ 77 SqlSession session=getSqlSessionFactory().openSession(); 78 try{ 79 Object obj=session.insert("com.gp.dao.UserMapper.delete", 6); 80 //执行完修改后一定要手动提交 81 session.commit(); 82 System.out.println(obj); 83 }finally{ 84 session.close(); 85 } 86 } 87 88 public static void main(String[] args) { 89 TestUser tu=new TestUser(); 90 // tu.selectUser(); 91 // tu.insertUser(); 92 // tu.updateUser(); 93 tu.deleteUser(); 94 } 95 }
至此,简单的mybatis的增删改查就完成了,以下说明几点;
1.配置文件mybatis-config.xml主要负责数据源的配置,以及映射实体类的映射文件
2.映射文件UserMapper.xml主要负责SQL语句的编写,并返回结果,实现数据最基本的增删改查
3.编写测试文件时,需要先加载配置文件,把配置文件以数据流的形式进行读取,根据读取的数据流创建SQLSessionFactory工厂,由SqlSessionFactory获取Sqlsession
获取SQLSession就可以执行对应的SQL语句,执行SQL语句
直接使用SqlSession的select,insert,update,delete方法进行对应的增删改查操作,有两个参数:
第一个参数是sql语句定位到映射文件UserMapper.xml文件的参数,是mapper映射文件中 namespace+id名,namespace具体定位到执行那个映射文件,id名具体定位执行那个SQL语句;
第二个参数是SQL语句的参数取值,例如插入语句传入的就是对象User,查询传入的就是id号。
上面是通过XML映射文件进行对数据的操作,还有一种方式,可以通过接口的方式进行操作数据的增删改查,下面举个简单的实例,如下所示:
实体类User不变,新增加一个接口文件UserMapper1.java,改变一下配置文件中的namespace,namespace是此接口的全类名,而增删改查标签中的id对应UserMapper1接口中对应的方法名,代码如下所示:
接口UserMapper1.java
1 package com.gp.dao; 2 3 public interface UserMapper1 { 4 public void insertUser(User user); 5 public User selectUser(Integer id); 6 public void updateUser(User user); 7 public void deleteUser(Integer id); 8 }
对应的映射文件如下:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.gp.dao.UserMapper1"><!-- 此处路径是接口UserMapper1的路径全类名 --> 6 <select id="selectUser" resultType="com.gp.dao.User"><!-- 此处的id表示接口中的方法名 --> 7 select * from user where id =#{id} 8 </select> 9 <insert id="insertUser"> 10 insert into user(id,name,password) values(#{id},#{name},#{password}) 11 </insert> 12 <!-- parameterType参数可以省略,也可以写上 -限制全类名 --> 13 <update id="updateUser" parameterType="com.gp.dao.User"> 14 update user set name=#{name} ,password=#{password} where id=#{id} 15 </update> 16 <delete id="deleteUser"> 17 delete from user where id=#{id} 18 </delete> 19 </mapper>
下面的测试类仅测试下查询方法,代码如下所示:
1 package com.gp.test; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 import org.apache.ibatis.io.Resources; 7 import org.apache.ibatis.session.SqlSession; 8 import org.apache.ibatis.session.SqlSessionFactory; 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 10 11 import com.gp.dao.User; 12 import com.gp.dao.UserMapper1; 13 14 public class TestUser1 { 15 16 //编写获取SqlSessionFactory的静态方法 17 public static SqlSessionFactory getSqlSessionFactory() { 18 String resource = "mybatis-config.xml"; 19 InputStream inputStream; 20 try { 21 inputStream = Resources.getResourceAsStream(resource); 22 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() 23 .build(inputStream); 24 return sqlSessionFactory; 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } 28 return null; 29 } 30 31 //实现查询方法 32 public void selectUser() { 33 34 SqlSession session = getSqlSessionFactory().openSession(); 35 36 try { 37 UserMapper1 mapper = session.getMapper(UserMapper1.class); 38 User user = mapper.selectUser(1); 39 40 System.out.println(user); 41 } finally { 42 session.close(); 43 } 44 } 45 public static void main(String[] args) { 46 TestUser1 tu1=new TestUser1(); 47 tu1.selectUser(); 48 } 49 }
测试的结果截图如下所示;
具体可以查看mybatis的参考手册
关于参数的处理:
单个参数:mybatis不会做特殊处理,#{参数名},直接取出就可以了,即使#{}中的参数名称和实体类User中的id名称不一致,依然会查询出结果,例如上面实例中配置文件的select标签中的参数改为#{idname}
多个参数:按照正常逻辑,select标签中的查询条件有2个,一个id,一个name,接口中新增一个方法,如下所示:
public User selectIdAndName(Integer id,String name);
映射文件中增加select标签如下所示:
1 <select id="selectIdAndName" resultType="com.gp.dao.User"> 2 select * from user where id =#{id} and name=#{name} 3 </select>
执行后会异常报错;Parameter 'id' not found. Available parameters are [1, 0, param1, param2]
原因:
mybatis遇到多个参数会做特殊处理,多个参数会被封装成一个map,key:param1....paramN
value表示传入的参数值,#{}就是从map中获取指定的key的值
正确的写法是:
<select id="selectIdAndName" resultType="com.gp.dao.User"> select * from user where id =#{param1} and name=#{param2} </select>
测试文件中获取对象的代码修改为:
UserMapper1 mapper = session.getMapper(UserMapper1.class); User user = mapper.selectIdAndName(1,"张三");
命名参数:明确指定封装参数值map的key,@param("id"),不建议使用param1...paramN,
多个参数被封装为一个map,
key:使用@param注释指定的值 value:参数值, #{指定的key}取出对应的参数值
实例修改如下所示,把接口中的方法修改为如下所示:
public User selectIdAndName(@Param("id")Integer id,@Param("name")String name);
把映射文件中的配置SQL修改为如下所示 :
<select id="selectIdAndName" resultType="com.gp.dao.User"> select * from user where id =#{id} and name=#{name} </select>
运行结果正常显示:
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入实体类User的对象即可,即pojo,#{属性名},取出传入的pojo的属性值
如果多个参数不是我们业务逻辑的数据模型,没有对应的map,为了方便,我们可以传入map对象,#{key},取出map中对应的值
在UserMapper1接口中增加如下方法:
public User getUserMap(Map<String,Object> map);
修改的测试类TestUser1.java如下所示:
UserMapper1 mapper = session.getMapper(UserMapper1.class); Map<String ,Object> map=new HashMap<String,Object>(); map.put("id", 1); map.put("name", "张三"); User user=mapper.getUserMap(map); System.out.println(user);
可以得出测试结果:
2018-03-17 11:47:27,958 [main] DEBUG [com.gp.dao.UserMapper1.getUserMap] - ==> Preparing: select * from user where id =? and name=? 2018-03-17 11:47:27,984 [main] DEBUG [com.gp.dao.UserMapper1.getUserMap] - ==> Parameters: 1(Integer), 张三(String) 2018-03-17 11:47:28,000 [main] DEBUG [com.gp.dao.UserMapper1.getUserMap] - <== Total: 1 User [id=1, name=张三, password=123456]
若多个参数不经常使用,可以传入map中,但要是经常使用,推荐编写一个TO(Transfer object)数据传输对象
Page{
int index;
int size;
}
获取参数的时候,有两种方式,一种是${},一种是#{}
两者都可以获取map中的值或者pojo对象中属性的值。
两者的区别是什么呢?
#{}是以预编译的形式将参数设置到SQL语句中的,Preparedstatment
${}取出的值直接拼装到SQL语句中,会有安全问题,
大多情况下,取参数的值都是使用#{},
原生jdbc不支持占位符的地方可以使用${}进行取值,比如分表,排序,表名等
select * from ${year}_salary where xxx;
select * from user order by ${name} ${order}
select * from ${tableName} where xxx;
=======================================================================
特别注意:,如果是Collocation(List,set)或者数组,也会特殊处理,把传入的list或者数组封装在map中,key:Collection(collection),list还可以使用key(list),数组(array)
例如:public User getUserId(List<Integer> ids); 取值,取出第一个id的值,#{list[0]},不能是#{param1[0]}也不能是#{ids[0]}