mybatis学习一:基于xml与注解配置入门实例与问题
注:本case参考自:http://www.cnblogs.com/ysocean/p/7277545.html
一:Mybatis的介绍:
- MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
- iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。
- MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。
二:基于xml配置的入门实例与介绍(idea的maven项目):
1:case项目结构如图:(pom文件)
几点注意:
-
- 有可能idea下Maven项目会很卡,那么调整:Other Setting->default Setting->搜索maven->Runner中:VM Options设置为:-DarchetypeCatalog=internal;
- main目录下的java使我们自己建的,要将java->右键->Mark Directory as设置为root(否则底下不能建立包文件);
pom.xml如下:
<?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:pom文件的模型版本 关于group id和artifact id,为了便于多人多模块协同开发管理(以后会讲),建议使用以下命名规范 group id:com.公司名.项目名 artifact id:功能模块名 packaging:项目打包的后缀,war是web项目发布用的,默认为jar version: artifact模块的版本 name和url:相当于项目描述,可删除 group id + artifact id +version :项目在仓库中的坐标 --> <modelVersion>4.0.0</modelVersion> <groupId>com.company.project</groupId> <artifactId>module</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>test Maven Webapp</name> <url>http://maven.apache.org</url> <!--上面这部分必须有--> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.0</version> </dependency> <!--<dependency>这里的jdbc的数据库连接jar总是报错,可以注释掉后从外部导入jar <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.7-bin</version> </dependency>--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </project>
2、创建数据库表:
1 create database spring_mybatis_test1; 2 use spring_mybatis_test1; 3 create table user( 4 id int(20) not null auto_increment, 5 username varchar(50) , 6 sex varchar(10), 7 birthday date, 8 address varchar(100), 9 primary key(id) 10 );
向其中插入一条数据: insert into user(id,username,sex,birthday,address,) values(1,‘tom’,‘男’,'1993-05-25','earth');
补充:下面将要用到的配置参数:
①、parameterType:指定输入参数的类型
②、resultType:指定输出结果的类型,在select中如果查询结果是集合,那么也表示集合中每个元素的类型
③、#{}:表示占位符,用来接收输入参数,类型可以是简单类型,pojo,HashMap等等
如果接收简单类型,#{}可以写成 value 或者其他名称
如果接收 pojo 对象值,通过 OGNL 读取对象中的属性值,即属性.属性.属性...的方式获取属性值
④、${}:表示一个拼接符,会引起 sql 注入,不建议使用
用来接收输入参数,类型可以是简单类型,pojo,HashMap等等
如果接收简单类型,${}里面只能是 value
如果接收 pojo 对象值,通过 OGNL 读取对象中的属性值,即属性.属性.属性...的方式获取属性值
3:Mybatis的配置文件mybatis-configuration.xml:(事务,dataSource,userMapper.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> <!-- 注意:environments标签,当mybatis和spring整合之后,这个标签是不用配置的 --> <!-- 可以配置多个运行环境,但是每个 SqlSessionFactory 实例只能选择一个运行环境 一、development:开发模式 二、work:工作模式--> <environments default="development"> <!--id属性必须和上面的default一样 --> <environment id="development"> <!--事务管理器 一、JDBC:这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围 二、MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期 比如 spring 或 JEE 应用服务器的上下文,默认情况下,它会关闭连接。然而一些容器并不希望这样, 因此如果你需要从连接中停止它,就可以将 closeConnection 属性设置为 false,比如: <transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager> --> <transactionManager type="JDBC"/> <!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/spring_mybatis_test1"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <!-- 注册userMapper.xml文件, userMapper.xml位于com.ys.mapper这个包下,所以resource写成com/ys/mapper/userMapper.xml--> <mapper resource="mapping/userMapping.xml"/> </mappers> </configuration>
4:实体类和映射文件userMapper.xml
- 实体类User:
1 package com.spring.model; 2 3 import java.util.Date; 4 public class User { 5 private int id; 6 private String username; 7 private String sex; 8 private Date birthday; 9 private String address; 10 public int getId() { 11 return id; 12 } 13 public void setId(int id) { 14 this.id = id; 15 } 16 public String getUsername() { 17 return username; 18 } 19 public void setUsername(String username) { 20 this.username = username; 21 } 22 public String getSex() { 23 return sex; 24 } 25 public void setSex(String sex) { 26 this.sex = sex; 27 } 28 public Date getBirthday() { 29 return birthday; 30 } 31 public void setBirthday(Date birthday) { 32 this.birthday = birthday; 33 } 34 public String getAddress() { 35 return address; 36 } 37 public void setAddress(String address) { 38 this.address = address; 39 } 40 @Override 41 public String toString() { 42 return "User [id=" + id + ", username=" + username + ", sex=" + sex 43 + ", birthday=" + birthday + ", address=" + address + "]"; 44 } 45 }
- 映射文件:注意36-49行的自增主键获取
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="user"><!--注意namespace的名称,测试文件中直接引用namespace--> 6 7 <!-- 根据 id 查询 user 表中的数据 8 id:唯一标识符,此文件中的id值不能重复 9 resultType:返回值类型,一条数据库记录也就对应实体类的一个对象 10 parameterType:参数类型,也就是查询条件的类型 11 --> 12 <select id="selectUserById" 13 resultType="com.spring.model.User" parameterType="int"> 14 <!-- 这里和普通的sql 查询语句差不多,后面的 #{id}表示占位符,里面不一定要写id,写啥都可以,但是不要空着 --> 15 select * from user where id = #{id} 16 </select> 17 18 <!-- 查询 user 表的所有数据 19 注意:因为是查询所有数据,所以返回的应该是一个集合,这个集合里面每个元素都是User类型 20 --> 21 <select id="selectUserAll" resultType="com.spring.model.User"> 22 select * from user 23 </select> 24 25 <!-- 模糊查询:根据 user 表的username字段 26 下面两种写法都可以,但是要注意 27 1、${value}里面必须要写value,不然会报错 28 2、${}表示拼接 sql 字符串,将接收到的参数不加任何修饰拼接在sql语句中 29 3、使用${}会造成 sql 注入 30 --> 31 <select id="selectLikeUserName" resultType="com.spring.model.User" parameterType="String"> 32 select * from user where username like '%${value}%' 33 <!-- select * from user where username like #{username} --> 34 </select> 35 36 <!-- 向 user 表插入一条数据 --> 37 <insert id="insertUser" parameterType="com.spring.model.User"> 38 <!-- 将插入的数据主键返回到 user 对象中 39 keyProperty:将查询到的主键设置到parameterType 指定到对象的那个属性 40 select LAST_INSERT_ID():查询上一次执行insert 操作返回的主键id值,只适用于自增主键 41 resultType:指定 select LAST_INSERT_ID() 的结果类型 42 order:AFTER,相对于 select LAST_INSERT_ID()操作的顺序 43 --> 44 <selectKey keyProperty="id" resultType="int" order="AFTER"> 45 select LAST_INSERT_ID() 46 </selectKey> 47 insert into user(username,sex,birthday,address) 48 value(#{username},#{sex},#{birthday},#{address}) 49 </insert> 50 51 <!-- 根据 id 更新 user 表的数据 --> 52 <update id="updateUserById" parameterType="com.spring.model.User"> 53 update user set username=#{username} where id=#{id} 54 </update> 55 56 <!-- 根据 id 删除 user 表的数据 --> 57 <delete id="deleteUserById" parameterType="int"> 58 delete from user where id=#{id} 59 </delete> 60 </mapper>
5:测试类:;
1 package com.ys.test; 2 3 import java.io.InputStream; 4 import java.util.List; 5 6 import org.apache.ibatis.session.SqlSession; 7 import org.apache.ibatis.session.SqlSessionFactory; 8 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 9 import org.junit.Before; 10 import org.junit.Test; 11 14 public class CRUDTest { 15 //定义 SqlSession 16 SqlSession session =null; 17 18 @Before 19 public void init(){ 20 //定义mybatis全局配置文件 21 String resource = "mybatis-configuration.xml"; 22 //加载 mybatis 全局配置文件 23 InputStream inputStream = CRUDTest.class.getClassLoader().getResourceAsStream(resource); 25 //构建sqlSession的工厂 26 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 27 //根据 sqlSessionFactory 产生 session 28 session = sessionFactory.openSession(); 29 } 30 31 //根据id查询user表数据 32 @Test 33 public void testSelectUserById(){ 34 /*这个字符串由 userMapper.xml 文件中 两个部分构成 35 <mapper namespace="user"> 的 namespace 的值 36 <select id="selectUserById" > id 值*/ 37 String statement = "user.selectUserById"; 38 User user = session.selectOne(statement, 1); 39 System.out.println(user); 40 session.close(); 41 } 42 43 //查询所有user表所有数据 44 @Test 45 public void testSelectUserAll(){ 46 String statement = "user.selectUserAll"; 47 List<User> listUser = session.selectList(statement); 48 for(User user : listUser){ 49 System.out.println(user); 50 } 51 session.close(); 52 } 53 54 //模糊查询:根据 user 表的username字段 55 @Test 56 public void testSelectLikeUserName(){ 57 String statement = "user.selectLikeUserName"; 58 List<User> listUser = session.selectList(statement, "%t%"); 59 for(User user : listUser){ 60 System.out.println(user); 61 } 62 session.close(); 63 64 } 65 //向 user 表中插入一条数据 66 @Test 67 public void testInsertUser(){ 68 String statement = "user.insertUser"; 69 User user = new User(); 70 user.setUsername("Bob"); 71 user.setSex("女"); 72 session.insert(statement, user); 73 //提交插入的数据 74 session.commit(); 75 session.close(); 76 } 77 78 //根据 id 更新 user 表的数据 79 @Test 80 public void testUpdateUserById(){ 81 String statement = "user.updateUserById"; 82 //如果设置的 id不存在,那么数据库没有数据更改 83 User user = new User(); 84 user.setId(4); 85 user.setUsername("jim"); 86 session.update(statement, user); 87 session.commit(); 88 session.close(); 89 } 91 92 //根据 id 删除 user 表的数据 93 @Test 94 public void testDeleteUserById(){ 95 String statement = "user.deleteUserById"; 96 session.delete(statement,4); 97 session.commit(); 98 session.close(); 99 } 100 }
结果:以下我只测试了testSelectUserById和testSelectLikeUserName,两个是一样的: User [id=1, username=tom, sex=男, birthday=Tue May 25 00:00:00 CST 1993, address=earth] 。
6:获取主键值:
- 数据库有自增主键:映射配置中的36-49行
1 <!-- 向 user 表插入一条数据 --> 2 <insert id="insertUser" parameterType="com.ys.po.User"> 3 <!-- 将插入的数据主键返回到 user 对象中 4 keyProperty:将查询到的主键设置到parameterType 指定到对象的那个属性 5 select LAST_INSERT_ID():查询上一次执行insert 操作返回的主键id值,只适用于自增主键 6 resultType:指定 select LAST_INSERT_ID() 的结果类型 7 order:AFTER,相对于 select LAST_INSERT_ID()操作的顺序 8 --> 9 <selectKey keyProperty="id" resultType="int" order="AFTER"> 10 select LAST_INSERT_ID() 11 </selectKey> 12 insert into user(username,sex,birthday,address) 13 value(#{username},#{sex},#{birthday},#{address}) 14 </insert>
- 非自增主键:
1 <!-- 向 user 表插入一条数据 --> 2 <insert id="insertUser" parameterType="com.ys.po.User"> 3 <!-- 将插入的数据主键返回到 user 对象中 4 流程是:首先通过 select UUID()得到主键值,然后设置到 user 对象的id中,在进行 insert 操作 5 keyProperty:将查询到的主键设置到parameterType 指定到对象的那个属性 6 select UUID():得到主键的id值,注意这里是字符串 7 resultType:指定 select UUID() 的结果类型 8 order:BEFORE,相对于 select UUID()操作的顺序 9 --> 10 <selectKey keyProperty="id" resultType="String" order="BEFORE"> 11 select UUID() 12 </selectKey> 13 insert into user(id,username,sex,birthday,address) 14 value(#{id},#{username},#{sex},#{birthday},#{address}) 15 </insert>
三:基于注解配置的入门实例与介绍(idea的maven项目):
1:我们直接在上面的case中配置注解方式,整个目录结构如下:
需要改动的地方包括以上三个部分:
2:不需要动的部分
- pom.xml不需要改动;
- User实体bean不需要改动;
- userMapping.xml弃用
3、定义操作user表的注解接口UserMapper.java(接口)
1 package com.spring.model; 2 3 import org.apache.ibatis.annotations.Delete; 4 import org.apache.ibatis.annotations.Insert; 5 import org.apache.ibatis.annotations.Select; 6 import org.apache.ibatis.annotations.Update; 7 8 public interface UserMapper { 9 10 //根据 id 查询 user 表数据 11 @Select("select * from user where id=#{id}") 12 public User selectUserById(int id) throws Exception; 13 14 //箱user插入一条数据 15 @Insert("insert into user(username,sex,birthday,address) values(#{username},#{sex},#{birthday},#{address})") 16 public void insertUser(User user) throws Exception; 17 18 //根据 id 修改 user 表数据 19 @Update("update user set username=#{username},sex=#{sex} where id=#{id}") 20 public void updateUserById(User user) throws Exception; 21 22 //根据 id 删除 user 表数据 23 @Delete("delete from user where id=#{id}") 24 public void deleteUserById(int id) throws Exception; 25 }
4、mybatis-configuration.xml中注册映射接口UserMapper.java
1 ...... 2 <mappers> 3 <!-- xml方式,注册userMapper.xml文件, 4 userMapper.xml位于com.ys.mapper这个包下,所以resource写成com/ys/mapper/userMapper.xml 5 <mapper resource="mapping/userMapping.xml"/>--> 6 <mapper class="com.spring.model.UserMapper"></mapper> 7 </mappers>
5、创建测试类
1 package com.spring; 2 3 import com.spring.CRUDTest; 4 import com.spring.model.User; 5 import com.spring.model.UserMapper; 6 import org.apache.ibatis.session.SqlSession; 7 import org.apache.ibatis.session.SqlSessionFactory; 8 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 9 import org.junit.Before; 10 import org.junit.Test; 11 12 import java.io.InputStream; 13 14 public class TestAnnotationCRUD { 15 SqlSession session=null; 16 17 @Before 18 public void init(){ 19 //定义mybatis全局配置文件 20 String resource = "mybatis-configuration.xml"; 21 //加载 mybatis 全局配置文件 22 InputStream inputStream = CRUDTest.class.getClassLoader().getResourceAsStream(resource); 23 //构建sqlSession的工厂 24 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 25 //根据 sqlSessionFactory 产生 session 26 session = sessionFactory.openSession(); 27 } 28 29 //注解的增删改查方法测试 30 @Test 31 public void testAnncationCRUD() throws Exception { 32 //根据session获取 UserMapper接口 33 UserMapper userMapper = session.getMapper(UserMapper.class); 34 //调用selectUserById()方法 35 User user = userMapper.selectUserById(1); 36 System.out.println(user); 37 38 //调用 insertUser() 方法 39 User user1 = new User(); 40 user1.setUsername("aliks"); 41 user1.setSex("不详"); 42 userMapper.insertUser(user1); 43 44 //调用 updateUserById() 方法 45 User user2 = new User(); 46 user2.setId(6); 47 user2.setUsername("lbj"); 48 userMapper.updateUserById(user2); 49 50 //调用 () 方法 51 userMapper.deleteUserById(6); 52 53 session.commit(); 54 session.close(); 55 } 56 57 }
idea输出: User [id=1, username=tom, sex=男, birthday=Tue May 25 00:00:00 CST 1993, address=earth]
数据库结果:
注解配置使我们放弃了映射文件mapping.xml,需要接口实现数据库操作与到方法间的映射