MyBatis 学习(一)
1、什么是MyBatis? MyBatis有什么作用?
- MyBatis 是一款优秀的持久层框架,
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
2、如何获得MyBatis?
-
Maven依赖
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency>
3、持久化:
- (数据持久化)是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(jdbc),io文件持久化
- 生活:冷藏食品。。
- 为什么需要持久化:有些对象不能让他丢掉。需要持久化操作
4、持久层:
- Dao层、Service层、Controller层
- 完成持久化工作的代码块
- 层的界限十分明显。
二、第一个MyBatis程序
思路:搭建环境-》导入MyBatis依赖--》编码--》测试!
0、创建Maven项目导入mybatis相关依赖
<!--导入依赖--> <dependencies> <dependency> <!--mysql驱动--> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--mybatis--> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!--junit测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
1、在resource资源目录创建mybatis-config.xml :注册mysql驱动连接数据库
<!--configuration核心配置文件--> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!--注册mysql驱动--> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=ture&useUnicode=ture&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration>
2、创建mybatisUtils工具类:通过构建 SqlSessionFactory从而获取SQLSession
//2、构建 SqlSessionFactory从而获取SQLSession(工厂类-》商品) public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; // SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。 // 而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例 static { try { //获取SqlSqlSessionFactory 对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /*有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。 SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。 则可以通过 SqlSession 实例来直接执行已映射的 SQL 语句*/ public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } }
3、User实体类:与数据表的字段一致
//3、与数据库对应的实体类 public class User { private int id; private String username; private int password; ........ }
4、业务行为接口 UserDao
public interface UserDao { List<User> getUserList(); }
5、通过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"> <!--5、通过xml使用SqlSession--> <!--namespace绑定一个对应的UseDao/Mapper接口--> <mapper namespace="com.study.dao.UserDao"> <!--select查询语句:id:接口中的方法名;resultType:返回结果类型(实体类的全限定名)--> <select id="getUserList" resultType="com.study.pojo.User"> select * from mybatis.user </select> </mapper>
=================================================================== //原来的JDBC写法对比xml public class UserDaoImpl implements UserDao{ @Override public List<User> getUserList() { //连接数据库驱动 //sql语句 String str ="select * from mybatis.user" ; // 返回 Resultset 结果集 return .....; } }
6、测试类:
public class UserDaoTest { @Test public void test(){ //第一步:获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); //第二步:执行SQL(如何拿到Sql,获取接口的class对象) UserDao userDao = sqlSession.getMapper(UserDao.class); //获得UserList集合 List<User> userList = userDao.getUserList(); //遍历输出 for (User user : userList) { System.out.println(user); } //关闭SQLSession sqlSession.close(); } }
7、在运行mybatis是出现的错误及解决方法

-
解决:原因是在构建SqlSession失败,在config.xml中找到没有将配置好的Mapper.xml添加到核心配置文件中去
即在configuration加入下面语句:
<!--每一个Mapper.xml都需要在mybatis核心配置文件中注册!--> <mappers> <mapper resource="com/study/dao/UserMapper.xml"/> </mappers>
问题二:

解决:这是运行时没有发现创建在java下的xml文件,则需要在Maven配置(最好在父子工程下的poml文件都配置)
<!--maven由于他的约定大于配置,我们之后再写配置,无法被导出或者生效的问题--> <!--在build中配置resource,来防止我们资源导出失败的问题--> <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>
问题三:

解决:这个问题解决了好长时间是由于粗心编码错误问题(公共变量的定义),因为SQLSessionFactory在外面已经定义,里面无需再定义,否侧拿到到的一直是null值

问题四:【true】

成功运行:

问题五
IDEA打包是遇到的错误(package:主要是为了看清楚Taget目录下有多少文件可以编译运行)

-
在使用打包是应该在pom中添加maven在
//build标签中 <!--package打包插件--> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.4.2</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> </plugins>
<properties> <!--Maven 打包时有标题中警告,需要在pom.xml文件中添加--> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
三、基本理论
1、SqlSessionFactoryBuilder
-
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
-
可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
2、SqlSessionFactory
-
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
-
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
-
使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
3、SqlSession
-
SqlSession sqlSession = sqlSessionFactory.openSession();
-
每个线程都应该有它自己的 SqlSession 实例。
-
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
-
绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
四、CRUD
1、namespace
-
命名空间的作用有两个,一个是利用更长的全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定。
-
长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。
-
命名解析:
- 全限定名(比如 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及使用。
-
注:namespace的命名就是dao/mapper接口的全限定名。
2、Select 查询
- id:就是对应的namespace(接口)中的方法名;
- resultType:Sql语句执行的返回值类型;
- parameterType:传参的类型;
UserMapper接口:所要实现的功能
-
/*4、功能接口*/ public interface UserDaoMapper { //查询所有用户 List<User> getUserList(); //通过id查询用户 User getUserById(int id); //添加用户 boolean insertUser(User user); //修改用户 boolean updataUser(User user); //删除用户 boolean deleteUser(int id); }
UserMapper.xml:查询语句(实现接口)
-
<!--select查询语句:id:接口中的方法名;resultType:返回结果类型(实体类的全限定名)--> <select id="getUserList" resultType="com.study.pojo.User"> select * from mybatis.user </select> <!--通过id查询用户--> <select id="getUserById" parameterType="int" resultType="com.study.pojo.User" > select * from mybatis.user where id = #{id} </select>
UserTest测试:
-
/*通过id查询用户*/ @Test public void getUserById(){ //1.获取sqlsession SqlSession sqlSession = MyBatisUtils.getSqlSession(); //获得Mapper对象(获得接口) UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class); //执行sql并返回结果 User user = mapper.getUserById(1); System.out.println(user); //关闭 sqlSession.close(); }
3、Insert 插入
UserMapper.xml:查询语句(实现接口)
-
<!--添加用户(User对象的属性可以直接取出来)--> <insert id="insertUser" parameterType="com.study.pojo.User" > insert into mybatis.user (id,username,password) values (#{id},#{username},#{password}) </insert>
UserTest测试:
-
/*增删改都需要提交事务*/ /*添加用户*/ @Test public void insertUser(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class); boolean user = mapper.insertUser(new User(6,"lijing2",2444)); System.out.println(user); sqlSession.commit(); sqlSession.close(); }
4、Delete 删除
UserMapper.xml:查询语句(实现接口)
-
<!--删除用户--> <delete id="deleteUser" parameterType="int"> delete from mybatis.user where id=#{id} </delete>
UserTest测试:
-
/*删除用户*/ @Test public void deleteUser(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class); boolean user = mapper.deleteUser(6); System.out.println(user); sqlSession.commit(); sqlSession.close(); }
5、Update 修改
UserMapper.xml:查询语句(实现接口)
-
<!--通过id修改用户--> <update id="updataUser" parameterType="com.study.pojo.User" > update mybatis.user set username = #{username},password= #{password} where id =#{id} </update>
UserTest测试:
-
/*更新用户*/ @Test public void updataUser(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class); boolean user = mapper.updataUser(new User(5, "哈哈", 00000000)); System.out.println(user); sqlSession.commit(); sqlSession.close(); }
注: 增删改都需要提交事务commit,数据库才会更新。
6、万能的Map
假设,我们的实体类有很多属性,或者数据库中的表,字段或者参数过多,就应当考虑使用Map!
-
使用map作为参数传递是不需要知道数据有什么子段。
-
在Sql语句编写是字段可以自定义不必和数据的字段一致。
-
//通过map查询用户 boolean addUserMap(Map<String,Object> map);
<!--使用map添加用户(不用静User的所有属性写出来也不用new User)--> <insert id="addUserMap" parameterType="map" > insert into mybatis.user (id,username,password) values (#{userid},#{name},#{pwd}) </insert>
/*通过map添加用户*/ @Test public void addUserMap(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserDaoMapper mapper = sqlSession.getMapper(UserDaoMapper.class); /*创建Map对象*/ Map<String, Object> map = new HashMap(); map.put("userid",6); map.put("name","opop"); map.put("pwd",88888); boolean userMap = mapper.addUserMap(map); System.out.println(userMap); sqlSession.commit(); sqlSession.close(); }
-
Map传递参数,直接在sql中取出key即可 【parameterType="map"】
-
而对象传递参数,直接在sql中取对象的属性即可【parameterType="类的全限定名"】
-
只有一个基本类型参数的情况下,可以直接在sql取到!
-
多个参数用Map,或者注解!
7、Like模糊查询
-
第一种:java代码执行的时候,传递通配符%%
List<User> userLike = mapper.getUserLike("%哈%");
<select id="getUserLike" resultType="com.study.pojo.User"> select * from mybatis.user where username LIKE #{value} </select>
-
第二种:在SQL拼接中使用通配符
<select id="getUserLike" resultType="com.study.pojo.User"> select * from mybatis.user where username LIKE "%"#{value}"%" </select>
List<User> userLike = mapper.getUserLike("哈");
五、配置解析
- MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
环境配置:
- MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。
- 不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
- 事务管理器(transactionManager)
- 在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
- 连接池:POOLED
- 如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个
configuration(配置) properties(属性) settings(设置) typeAliases(类型别名) environments(环境配置) environment(环境变量) transactionManager(事务管理器) dataSource(数据源) databaseIdProvider(数据库厂商标识) mappers(映射器)
1、属性设置之配置优化
- 属性(properties)
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
-
我们可以通过properties属性来实现引用配置问文件。
-
1、db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8 username=root password=root
-
2、在配置文件中引入
-
注:配置文件中引入要注意其顺序
-
<!--1、configuration核心配置文件--> <configuration> <!--引入外部配置文件--> <properties resource="db.properties"/> <!--默认环境--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <!--连接的数据源--> <dataSource type="POOLED"> <!--注册mysql驱动--> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!--每一个Mapper.xml都需要在Mybatis核心配置文件注册!--> <mappers> <mapper resource="com/study/dao/UserMapper.xml"/> </mappers> </configuration>
或:这样的写法 <properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="root"/> </properties>
-
可以直接引入外部文件
-
可以在其中增加一些属性配置】
-
如果两个文件有同一个字段,优先使用外部引用的文件!
2、类型别名(typeAliases)
-
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写
-
我们在xml编写sql时需要指定resultType就是全限定类名这是就可以简化
-
第一种方式:
<!--简化全限定类名,起别名--> <typeAliases> <typeAlias type="com.study.pojo.User" alias="User"/> </typeAliases>
<select id="getUserList" resultType="User"> select * from mybatis.user </select>
-
第二种:也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<!--扫描包名,会默认使用 Bean 的首字母小写的非限定类名来作为它的别名--> <typeAliases> <package name="com.study.pojo"/> </typeAliases>
<select id="getUserList" resultType="user"> select * from mybatis.user </select>
每一个在包com.study.pojo 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。
- 在实体类比较少的时候,使用第一种方式
- 如果实体类非常多的情况下,建议使用第二种。
- 第一种可以diy别名,第二种需要diy的则需加在类上加注解@@Alias()
@Alias("UserPoJo") public class User { private int id; private String username; private int password; ...... }
<!--扫描包名,会默认使用 Bean 的首字母小写的非限定类名来作为它的别名--> <typeAliases> <package name="com.study.pojo"/> </typeAliases>
<select id="getUserList" resultType="UserPoJo"> select * from mybatis.user </select>
3设置(settings)
- 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。 | true | false | False |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |

4、其他配置
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
- maven:mybatis-generator_core
- mybatis-plus
- 通用mapper
5、映射器(Mapper)
- 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括
file:///
形式的 URL),或类名和包名等。 - MapperRegistry:注册绑定我们的Mapper文件
方式一:
-
<!--每一个Mapper.xml都需要在mybatis核心配置文件中注册!--> <mappers> <mapper resource="com/study/dao/UserMapper.xml"/> </mappers>
方式二:使用class文件绑定注册
-
<!--每一个Mapper.xml都需要在mybatis核心配置文件中注册!--> <mappers> <mapper class="com.study.dao.UserMapper"/> </mappers>
-
注意点:
- 1、接口和他的Mapper配置文件必须同名!
- 2、接口和他的Mapper配置文件必须在同一个包下!
方式三:使用扫描包进行注入绑定
-
<mappers> <package name="com.study.dao"/> </mappers>
注意点:
- 1、接口和他的Mapper配置文件必须同名!
- 2、接口和他的Mapper配置文件必须在同一个包下!
6、作用域(Scope)和生命周期
SqlSessionFactoryBuilder
-
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory
- 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。因此 SqlSessionFactory 的最佳作用域是应用作用域。
SqlSession
-
SqlSession sqlSession = sqlSessionFactory.openSession();
-
每个线程都应该有它自己的 SqlSession 实例。
-
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
