Mybatis
Mybatis
1、什么是Mybatis?
历史
MyBatis 本是apache的一个开源项目iBatis
2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis
2013年11月迁移到Github
定义
一个基于Java的持久层框架
支持定制化 SQL、存储过程以及高级映射
避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 Pojos(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录
Mybatis相关资料
2、持久化和持久层
持久化
把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)
持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等
持久化是将程序数据在持久状态和瞬时状态间转换的机制
JDBC就是一种持久化机制,文件IO也是一种持久化机制
持久层
完成持久化工作的代码块
3、第一个Mybatis程序
环境搭建
建数据库以及表
新建Maven项目后在pom.xml中导入依赖
<!--mysql依赖--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version></dependency>?<!--mybatis依赖--><dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version></dependency>?<!--Lombok依赖--><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version></dependency>
编写Mybatis配置文件: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核心配置文件--><configuration> <!--可以配置多种环境,如开发、测试,default指定用的是哪种环境--> <environments default="development"> <environment id="development"> <!--决定事务范围和控制方式的事务管理器--> <transactionManager type="JDBC"/> <!--获取数据库连接实例的数据源--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments></configuration>
编写Mybatis工具类
1、构建SqlSessionFactory
每个基于Mybatis的应用都是以一个SqlSessionFactory的实例为核心的
SqlSessionFactoryBuilder可以从XML配置文件或者一个预先定制的Configuration的实例构建出SqlSessionFactory的实例
使用任意的输入流(InputStream)实例,通过字符串形式的文件路径,或者url形式的文件路径配置
Resources工具类可使从classpath或其他位置加载资源文件更加容易
2、从SqlSessionFactory中获取SqlSession
SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
SqlSession 实例来直接执行已映射的 SQL 语句
SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession 的生命周期和作用域
SqlSessionFactoryBuilder
一旦创建了 SqlSessionFactory,就不再需要SqlSessionFactoryBuilder了
最佳作用域是方法作用域(也就是局部方法变量)
SqlSessionFactory
一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃SqlSessionFactory或重新创建另一个实例
最佳作用域是应用作用域,最简单的就是使用单例模式或者静态单例模式
SqlSession
每个线程都应该有它自己的 SqlSession 实例
最佳的作用域是请求或方法作用域
public class MybatisUtils {? private static SqlSessionFactory sqlSessionFactory;? static { try { //使用mybatis第一步:获取sqlSessionFactory对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } }? //从 SqlSessionFactory 中获取 SqlSession public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); }}
编写代码
实体类
@Data@NoArgsConstructor@AllArgsConstructorpublic class User {? private Integer id; private String name; private String pwd;}
Dao接口,UserMapper
public interface UserMapper { List<User> getUserList();}
接口实现类,UserMapper.xml
<?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">?<!--namespace,绑定一个对应的mapper接口--><mapper namespace="com.hmx.dao.UserMapper"> <!-- id:sql语句对应的执行的方法名 resultType:返回结果,要写全限命名 --> <select id="getUserList" resultType="com.hmx.pojo.User"> select * from mybatis.mybatistest </select></mapper>
在mybatis的配置文件中给每个Mapper.xml配置mapper
<!--每一个Mapper.xml都需要在核心配置文件中注册--><mappers> <mapper resource="com/hmx/dao/UserMapper.xml"/></mappers>
测试
public class UserMapperTest { public static void main(String[] args) {? //第一步:获得SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession();? //获得mapper,执行sql语句 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.getUserList();? //输出结果 for (User user : userList) { System.out.println(user); } //关闭SqlSession sqlSession.close(); }}
注意点:常见错误
Type interface com.hmx.dao.UserDao is not known to the MapperRegistry
原因:Mapper.xml没有在核心配置文件中注册
解决:在mybatis的配置文件中给每个Mapper.xml配置mapper
<!--每一个Mapper.xml都需要在核心配置文件中注册--><mappers> <mapper resource="com/hmx/dao/UserMapper.xml"/></mappers>
Could not find resource com/hmx/dao/UserMapper.xml
原因:资源导入失败,Maven导出资源问题
解决:在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>
com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: 1 字节的 UTF-8 序列的字节 1 无效
原因:xml编码问题
解决:
1、在pom.xml中配置如下代码
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>
若方法1没用,参考
2、把每个xml文件的文件头
<?xml version="1.0" encoding="UTF-8" ?>
改为:
<?xml version="1.0" encoding="UTF8" ?>
4、增删改查
实体类:User
@Data@NoArgsConstructor@AllArgsConstructorpublic class User {? private Integer id; private String name; private String pwd;}
接口类:UserMapper
public interface UserMapper {? //查询所有数据 List<User> getUserList(); //根据id查询数据 User selectById(int id); //增加数据 int insertUser(User user); //更新数据 int updateUser(User user); //删除数据 int deleteUser(int id);}
接口类的实现UserMapper.xml
<?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"><!--namespace绑定一个mapper接口--><mapper namespace="com.hmx.dao.UserMapper">? <select id="getUserList" resultType="com.hmx.model.User"> select * from mybatis.mybatistest; </select>? <select id="selectById" parameterType="int" resultType="com.hmx.model.User"> select * from mybatis.mybatistest where id = #{id}; </select>? <insert id="insertUser" parameterType="com.hmx.model.User"> insert into mybatis.mybatistest (id,name,pwd) values (#{id},#{name},#{pwd}); </insert>? <update id="updateUser" parameterType="com.hmx.model.User"> update mybatis.mybatistest set name = #{name},pwd = #{pwd} where id = #{id}; </update>? <delete id="deleteUser"> delete from mybatis.mybatistest where id = #{id}; </delete></mapper>
测试
//查询所有数据public static void selectAll(){? //第一步:获得SqlSession对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //执行sal语句 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.getUserList(); for (User user : userList) { System.out.println(user); } //关闭SqlSession sqlSession.close();}?//根据id查询数据public static void selectById(){ SqlSession sqlSession = MybatisUtils.getSqlSession();? UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.selectById(1); System.out.println(user);? sqlSession.close();}?//添加数据public static void insertUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession();? UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.insertUser(new User(9,"大黄","123")); sqlSession.commit();? sqlSession.close();}?//修改数据public static void updateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession();? UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.updateUser(new User(4,"大黑子","333")); sqlSession.commit();? sqlSession.close();}?//删除数据public static void deleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession();? UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.deleteUser(9); sqlSession.commit();? sqlSession.close();}
5、注解实现增删改查
Mybatis注解作用:
使用注解来映射简单语句会使代码显得更加简洁
但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪
因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句
mybatis注解本质
本质:反射机制
底层:动态代理模式
注意点:
注解写在接口类中的方法上
使用注解开发不需要写接口的实现类(XXXMapper.xml)文件,所以在配置文件中需要绑定XXXMapper.java
<mappers> <mapper class="com.hmx.mapper.UserMapper"/></mappers>
@Param()注解
方法中只有一个参数,可加可不加,最好加,多个参数必须加
基本类型和String类型需要加上
和sql语句中引用的#{}相匹配
增删改查
public interface UserMapper {? //查询所有数据 @Select("select * from mybatis.mybatistest") List<User> getUserList(); //根据id查询数据 @Select("select * from mybatis.mybatistest where id = #{id}") User selectById(@Param("id") int id); //增加数据 @Insert("insert into mybatis.mybatistest (id,name,pwd) values (#{id},#{name},#{pwd})") int insertUser(User user); //更新数据 @Update("update mybatis.mybatistest set name = #{name},pwd = #{pwd} where id = #{id}") int updateUser(User user); //删除数据 @Delete("delete from mybatis.mybatistest where id = #{id};") int deleteUser(@Param("id") int id);}
6、Mybatis配置文件解析
configuration核心配置文件中包含了会深深影响 MyBatis 行为的设置和属性信息,可以配置如下配置:
properties(属性)
可以直接引入外部文件
<properties resource="db.properties"/>
#db.propertiesdriver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8username=rootpassword=root
如果db.properties中没有配置username和password,则可以可以在properties中增加一些属性配置
<properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="root"/></properties>
如果两个配置文件和properties中存在同一字段,如:都含有username这个字段但是值不一样,优先使用外部配置文件
settings(设置)
一个配置完整的settings元素的示例如下:
<settings> 1、<!--全局地开启或关闭所有映射器配置文件中已配置的任何缓存,有效值true|false,默认true--> <setting name="cacheEnabled" value="true"/> 2、<!-- 延迟加载的全局开关。 当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 有效值true|false,默认false --> <setting name="lazyLoadingEnabled" value="true"/> 3、<!--是否允许单个语句返回多结果集(需要数据库驱动支持),有效值true|false,默认true--> <setting name="multipleResultSetsEnabled" value="true"/> 4、<!-- 使用列标签代替列名 实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察 有效值true|false,默认true --> <setting name="useColumnLabel" value="true"/> 5、<!-- 允许 JDBC 支持自动生成主键,需要数据库驱动支持 如果设置为 true,将强制使用自动生成主键 尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby) 有效值true|false,默认false --> <setting name="useGeneratedKeys" value="false"/> 6、<!-- 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射 PARTIAL 只会自动映射没有定义嵌套结果映射的字段 FULL 会自动映射任何复杂的结果集(无论是否嵌套) 默认值为PARTIAL --> <setting name="autoMappingBehavior" value="PARTIAL"/> 7、<!-- 指定发现自动映射目标未知列(或未知属性类型)的行为。 NONE: 不做任何反应 WARNING: 输出警告日志 FAILING: 映射失败 (抛出 SqlSessionException) 默认值为NONE --> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> 8、<!-- 配置默认的执行器 SIMPLE 就是普通的执行器 REUSE 执行器会重用预处理语句(PreparedStatement) BATCH 执行器不仅重用语句还会执行批量更新 默认值为SIMPLE--> <setting name="defaultExecutorType" value="SIMPLE"/> 9、<!-- 设置超时时间,它决定数据库驱动等待数据库响应的秒数 有效值为任意正整数 默认未设置 (null) --> <setting name="defaultStatementTimeout" value="25"/> 10、<!-- 为驱动的结果集获取数量(fetchSize)设置一个建议值,此参数只可以在查询设置中被覆盖。 有效值为任意正整数 默认未设置 (null) --> <setting name="defaultFetchSize" value="100"/>