Mybatis-入门 [toc]
0、前导
框架简述:开发时为解决某些问题而使用的半成品软件,是一种解决方案。
使用框架的好处:封装了很多细节,提高了效率。
三层架构:
表现层:展现数据
业务层:处理业务
持久层:数据库交互
持久层的解决方案:
JDBC:Connection + PreparedStatement + ResultSet
Spring的JdbcTemplete:Spring对JDBC的简单封装
Apache的DBUtils
以上3种都只是工具,还算不上框架
1、Mybatis的概述 Mybatis是一款优秀的持久层框架 ,封装了JDBC,使得开发者只需要关注SQL本身。通过XML 或注解 的形式配置Statement,通过Java对象和Statement的动态参数 映射成为SQL语句。(Mybatis框架通过 ORM 解决了实体与数据库的映射问题)。
ORM 模型:(Object Relation Mapping)数据库的1张表 对应 1个Java实体类。
2、Mybatis的环境搭建
IDEA 新建 Maven工程(不选模板)
在 POM.xml中导入配置(前提是:已经配好maven环境)
pom.xml:【Mybatis的坐标可以直接官网复制,然后填写版本号】
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 <?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.cyw</groupId > <artifactId > MyBatisDemo_day01</artifactId > <version > 1.0-SNAPSHOT</version > <properties > <maven.compiler.source > 8</maven.compiler.source > <maven.compiler.target > 8</maven.compiler.target > </properties > <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.5</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.0.4</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.12</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 3.8.2</version > <scope > test</scope > </dependency > </dependencies > </project >
在包下创建 实体类(com.cyw.entity.User)
在包下创建 接口(com.cyw..dao.UserDao)、在接口中定义方法(findAll)
在Resource目录 下创建 Mybatis的主配置文件(SqlMapConfig.xml) (数据库的配置文件)
SqlMapConfig.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 <?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 default ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/mybatisdemo" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/cyw/dao/UserDao.xml" /> </mappers > </configuration >
在Resource目录 下创建1个映射配置文件 (与Dao接口的全类名相同的 xml文件)( com/cyw/dao/UserDao.xml )
1 2 3 4 5 6 7 8 9 10 11 <?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.cyw.dao.UserDao" > <select id ="findAll" resultType ="com.cyw.entity.User" > select * from user; </select > </mapper >
环境配置的注意要点:
接口的 xml 映射配置文件 和 接口的名字 要保持一致。(Dao也可以叫Mapper)
IDEA中,创建包 要用小数点 分割,创建目录 要用斜杠 分割
映射配置文件的目录结构 要与 接口的包结构 保持一致。
映射配置文件的Mapper标签的 namespace属性 的属性值必须是接口的全类名
映射配置文件的操作标签(select)的 id属性 的属性值必须是接口的方法名
遵循第3~5点好处:无需写dao接口的实现类。
环境配置小结:
配置maven的 pom.xml
在 src/main/resources/ 目录中创建SqlMapConfig.xml (mybatis全局配置),填写4个DB信息
创建实体类
创建 dao接口
创建 dao接口的 xml 配置文件
在 SqlMapConfig.xml 指定 dao接口配置文件的路径
在 dao接口的 xml 配置文件 中 指定 接口的全类名、要调用的接口方法、实体对象的全类名,sql语句。
创建1个获取 SqlSession的工具类
获取 SqlMapConfig.xml 的资源输入流
在 SqlSession工具类中创建SqlSeeesionBulider对象
SqlSeeesionBulider对象 根据 资源输入流 建造1个SqlSessionFatory对象
SqlSessionFatory对象 调用 OpenSqlSession( ) 获取 SqlSession
SqlSession 调用 getMapper(接口名.class) 得到 dao对象
dao对象 调用 接口的方法得到 结果集
3、Mybatis的入门案例 案例-踩坑:【log4j:ERROR call failed】
原因:虚拟机里没划分D盘,只有E盘
解决:打开 log4j.properties 文件,log4j.appender.LOGFILE.File 的值改为 e:\axis.log
log4j.properties 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 log4j.rootCategory =debug, CONSOLE, LOGFILE log4j.logger.org.apache.axis.enterprise =FATAL, CONSOLE log4j.appender.CONSOLE =org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout =org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern =%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n log4j.appender.LOGFILE =org.apache.log4j.FileAppender log4j.appender.LOGFILE.File =e:\axis.log log4j.appender.LOGFILE.Append =true log4j.appender.LOGFILE.layout =org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern =%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
踩坑-2:java.lang.ExceptionInInitializerError
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 在 pom.xml中加入 <build > <resources > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > <resource > <directory > src/main/java</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources > </build >
3.1 案例-1: 0. 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 <?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.cyw</groupId > <artifactId > MyBatisDemo_day01</artifactId > <version > 1.0-SNAPSHOT</version > <properties > <maven.compiler.source > 8</maven.compiler.source > <maven.compiler.target > 8</maven.compiler.target > </properties > <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.5</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.0.4</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.12</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 3.8.2</version > <scope > test</scope > </dependency > </dependencies > </project >
1. SQL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 create database `MybatisDemo`;use `MybatisDemo`; DROP TABLE IF EXISTS `user `;CREATE TABLE `user ` ( `id` int (11 ) NOT NULL auto_increment, `username` varchar (32 ) NOT NULL COMMENT '用户名称' , `birthday` datetime default NULL COMMENT '生日' , `sex` char (1 ) default NULL COMMENT '性别' , `address` varchar (256 ) default NULL COMMENT '地址' , PRIMARY KEY (`id`) ) ENGINE= InnoDB DEFAULT CHARSET= utf8; insert into `user `(`id`,`username`,`birthday`,`sex`,`address`) values (41 ,'老王' ,'2018-02-27 17:47:08' ,'男' ,'北京' ),(42 ,'小二王' ,'2018-03-02 15:09:37' ,'女' ,'北京金燕龙' ),(43 ,'小二王' ,'2018-03-04 11:34:34' ,'女' ,'北京金燕龙' ),(45 ,'传智播客' ,'2018-03-04 12:04:06' ,'男' ,'北京金燕龙' ),(46 ,'老王' ,'2018-03-07 17:37:26' ,'男' ,'北京' ),(48 ,'小马宝莉' ,'2018-03-08 11:44:00' ,'女' ,'北京修正' );
2. User 实体类 com/cyw/entity/User 实体类
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 package com.cyw.entity;import java.io.Serializable;import java.util.Date;public class User implements Serializable { private Integer id; private String username; private Date birthday; private String sex; private String address; public User () { } public User (Integer id, String username, Date birthday, String sex, String address) { this .id = id; this .username = username; this .birthday = birthday; this .sex = sex; this .address = address; } @Override public String toString () { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}' ; } 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 Date getBirthday () { return birthday; } public void setBirthday (Date birthday) { this .birthday = birthday; } public String getSex () { return sex; } public void setSex (String sex) { this .sex = sex; } public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } }
3. UserDao接口 com/cyw/dao/UserDao接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.cyw.dao;import com.cyw.entity.User;import java.util.List;public interface UserDao { List<User> findAll () ; }
4. log4j.properties 配置文件 src/main/resources/log4j.properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 log4j.rootCategory =debug, CONSOLE, LOGFILE log4j.logger.org.apache.axis.enterprise =FATAL, CONSOLE log4j.appender.CONSOLE =org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout =org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern =%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n log4j.appender.LOGFILE =org.apache.log4j.FileAppender log4j.appender.LOGFILE.File =e:\axis.log log4j.appender.LOGFILE.Append =true log4j.appender.LOGFILE.layout =org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern =%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
5. SqlMapConfig.xml src/main/resources/SqlMapConfig.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 <?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 default ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/mybatisdemo" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/cyw/dao/UserDao.xml" /> <mapper class ="com/cyw/dao/UserDao.xml" /> </mappers > </configuration >
6. UserDao.xml src/main/resources/com/cyw/dao/UserDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 <?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.cyw.dao.UserDao" > <select id ="findAll" resultType ="com.cyw.entity.User" > select * from user; </select > </mapper >
7. Main test/java/com/cyw/test/UserDaoTest
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 package com.cyw.test;import com.cyw.dao.UserDao;import com.cyw.entity.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;import java.util.List;public class UserDaoTest { public static void main (String[] args) throws Exception { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = builder.build(is); SqlSession sqlSession = sqlSessionFactory.openSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> users = userDao.findAll(); for (User user : users) { System.out.println(user); } sqlSession.close(); is.close(); 。 } }
8. 封装工具类 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 package com.cyw.utils;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;public class SqlSessionUtil { private static SqlSessionFactory factory; static { try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); factory = builder.build(is); } catch (Exception e) { e.printStackTrace(); } } public static SqlSession getSqlSession () { return factory.openSession(); } }
注意:
Dao配置文件的namespace的包名 要与dao / mapper 接口名 一致。
3.2 解决结果集的实体类属性与数据库中的字段名不一致的问题: 2种解决方案:
在SQL查询时,数据库字段取 别名。
dao的配置文件中定义1个ResultMap,指定 id 和 type(type为结果集实体类)。 在ResultMap标签内,定义Result标签,绑定Result标签的 column属性 (数据库字段) 和 property属性 (实体类的属性) 属性。定义Select标签的ResultMap属性= ResultMap的 id 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // resultMap中一般只指定【sql字段】与【结果集的实体类的属性】不一致的属性 // property:结果集实体类的属性 // column:数据表的列名 <resultMap id ="userResultMap" type ="User" > <id property ="id" column ="user_id" /> <result property ="username" column ="user_name" /> <result property ="password" column ="hashed_password" /> </resultMap > <select id ="selectUsers" resultMap ="userResultMap" > select user_id, user_name, hashed_password from some_table where id = #{id} </select >
3.3 配置日志 在mybatis的核心配置文件(SqlMapConfig.xml)中的Configuration标签下settings 标签中 配置日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 注意:setting标签下的 value属性的取值为: // NO_LOGGING // STDOUT_LOGGING // LOG4J 【前3个重点掌握】 // LOG4J2 // SLF4J // JDK_LOGGING // COMMONS_LOGGING <configuration > <settings > <setting name ="logImpl" value ="LOG4J" /> </settings > </configuration >
4、Mybatis的单表(CRUD) 注意: 在接口的配置文件中编写SQL语句时,传参数可以使用占位符#{实体类属性名}
,示例可参照案例2的第2步。
4.1 案例-2(CRUD): 在案例-1的基础上实现增删改查
前提:数据库、实体类都不变。
dao接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.cyw.mapper;import com.cyw.entity.User;import java.util.List;public interface UserMapper { List<User> findAll () ; User findUserById (int id) ; int delUser (int id) ; int insertUser (User user) ; int updateUser (User user) ; }
查找所有用户 (MybatisTest测试类中)
配置:(接口的xml配置文件的mapper标签内)
1 2 3 4 5 6 // id="findAll" 为接口的方法名 // resultType="com.cyw.entity.User" 为结果实体类的全类名 <select id ="findAll" resultType ="com.cyw.entity.User" > select * from mybatisdemo.user; </select >
执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void findAll () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.findAll(); for (User user : users) { System.out.println(user); } sqlSession.close(); }
查找单个用户
配置:
1 2 3 4 5 6 7 8 // id="findUserById" 为接口的方法名 // resultType="com.cyw.entity.User" 为结果实体类的全类名 // parameterType="int" 为方法调用时,所需传入的参数的类型 // #{传入的参数,即:实体类的属性} 为占位符 <select id ="findUserById" resultType ="com.cyw.entity.User" parameterType ="int" > select * from mybatisdemo.user where id=#{id}; </select >
执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void findUserById () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.findUserById(42 ); System.out.println(user); sqlSession.close(); }
删除用户
配置:
1 2 3 <delete id ="delUser" parameterType ="int" > delete from mybatisdemo.user where id=#{id}; </delete >
执行:
1 2 3 4 5 6 7 8 @Test public void delUser () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.delUser(41 ); sqlSession.commit(); sqlSession.close(); }
更新用户
配置:
1 2 3 <update id ="updateUser" parameterType ="com.cyw.entity.User" > update mybatisdemo.user set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address} where id=#{id}; </update >
执行:
1 2 3 4 5 6 7 8 @Test public void updateUser () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.updateUser(new User(50 ,"张三" ,new Date(3 ,1 ,1 ),"男" ,"石家庄" )); sqlSession.commit(); sqlSession.close(); }
4.2 SqlMapConfig.xml 的常用参数:
数据库连接信息:
1 2 3 4 5 6 7 8 9 10 // 1. SqlMapConfig 中,property可以定义在外部的properties文件中, // 然后通过SqlMapConfig配置文件的properties标签的resource属性引入。 // 2. 也可以直接将property写在properties标签内。 // 注意:当既有外部的properties、又有内部的properties时,优先使用外部的属性配置。 <properties resource ="com/cyw/db.properties" > <property name ="username" value ="cyw" /> <property name ="psw" value ="123" /> </properties >
结果集类取别名 :
1 2 3 4 5 6 7 8 9 10 11 12 13 // 指定全类名的别名(取在在具体的类上,可以自定义别名) <typeAliases > // 给1个类取别名 <typeAlias type ="com.cyw.entity.User" alias ="User" /> </typeAliases > // 指定全类名的别名(取在在具体的包上,不能自定义别名,只能是非限定类名,想自定义则必须配合注解使用) <typeAliases > // 给1个包取别名,然后在javabean的定义上使用注解:@Alias("user") <package name ="com.cyw.entity" /> </typeAliases >
数据库的连接环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // environments标签的 default属性 指定的是 内部environment标签的id <environments default ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/mybatisdemo" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > <environment id ="test" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/mybatisdemo" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments >
在上面的案例中,Mybatis在使用代理dao时,只干了2件事:
创建代理对象(getMapper方法获取的dao)
利用代理对象来调用 接口的方法
小结:
代理对象调用接口的方法(传入参数)=》接口的定义 =》接口的 xml 配置文件