文章目录
1 Mybatis
使用了 MyBatis 之后,只需要提供 SQL 语句就好,基于java的持久层框架。
持久层: 可以将业务数据存储到磁盘,具备长期存储能力,只要磁盘不损坏,在断电或者其他情况下,重新开启系统仍然可以读取到这些数据。
优点: 可以使用巨大的磁盘空间存储相当量的数据,并且很廉价;
缺点:慢(相对于内存而言)
GroupId,ArtifactId 统称为“坐标”是为了保证项目唯一性而提出的,如果你要把你项目弄到maven本地仓库去,你想要找到你的项目就必须根据这两个id去查找。
GroupId:定义了项目属于哪个组;
Artifacted:定义了当前maven项目在组中唯一的ID,项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。
1 demo
maven,webapp项目,实现单表增删改查
1.下载和搭建 MyBatis 的开发环境。
在【File】菜单下找到【Settings】,然后再【Plugins】下点击【Browse repositories…】
在搜索栏中输入【MyBatis Plugin】,然后点击【Install】
Free MyBatis plugin
2.步骤:
(1) pom.xml文件
// mybatis核心包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
// mysql驱动包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
(2) mybatis.xml文件
建立模板,方便下次新建xml文件:File–settings–Editor–File and Code Templates
<?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>
<!-- 加载 java 的配置文件或者声明属性信息 -->
<!-- <properties resource="db.properties"/> -->
<settings>
<!--当返回行的所有列都是空时, MyBatis 默认返回 null-->
<setting name="returnInstanceForEmptyRow" value="true"/>
<!--显示 sql 语句-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--数据库的字段名的下划线 => pojo 属性中的 驼峰命名法-->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
</settings>
<!-- 自定义别名 -->
<typeAliases>
<!-- 单个别名定义 -->
<!-- <typeAlias type="com.itheima.mybatis.po.User" alias="user"/> -->
<!-- 批量别名定义(推荐) -->
<!-- package:指定包名称来为该包下的 po 类声明别名,默认的别名就是类名(首字母大小写都可) -->
<!--<package name="com.hsj.pojo" />-->
</typeAliases>
<!-- 配置 mybatis 的环境信息,与 spring 整合,该信息由 spring 来管理 -->
<environments default="development">
<!--测试环境-->
<!--开发环境-->
<environment id="development">
<!--使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域-->
<transactionManager type="JDBC"/>
<!--使用数据池,复用实例-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/admin?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
<!--生产环境-->
</environments>
<mappers>
<!-- 映射文件方式 1,一个一个的配置
<mapper resource="com/hsj/pojo/UserMapper.xml"/>-->
<!-- 映射文件方式 2,自动扫描包内的 Mapper 接口与配置文件(推荐) -->
<!-- <package name="com/hsj/pojo"/> -->
<mapper resource="mapper/EmployeeMapper.xml"/>
</mappers>
</configuration>
注意:底层规定 标签顺序不可改变。
(3) pojo类
建立数据库连接,生成pojo类
添加无参构造器:反射时 映射 空对象
(4) 数据库映射XML
(5) 创建数据库操作对应的接口
EmployeeMapper.java
public interface EmployeeMapper {
List<Employee> findAll();
void addEmployee(Employee employee);
void updateEmployee(Employee employee);
Employee getEmployee(Employee employee);
void delEmployee(Employee employee);
}
快捷键:鼠标位于EmployeeMapper ,alt+enter
EmployeeMapper.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" >
<mapper namespace="com.java201.dao.EmployeeMapper">
<select id="findAll" resultType="com.java201.pojo.Employee">
select * from employee;
</select>
<insert id="addEmployee">
insert into employee values (#{id},#{ename},#{eage},#{employ})
</insert>
<delete id="delEmployee">
delete from employee where id=#{id}
</delete>
<select id="getEmployee" resultType="com.java201.pojo.Employee">
select * from employee where id=#{id}
</select>
<update id="updateEmployee">
update employee set ename=#{ename},eage=#{eage} where id=#{id}
</update>
</mapper>
(PS:接口里面的方法名和 mapper 里面的 id 要对应起来)
(6).控制器(测试类)
执行流程
@Test
public void testfindAll() {
try{
// 1. 加载核心配置文件
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 2. 创建session工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 创建session => 相当于数据库连接对象
SqlSession session = factory.openSession();
// 4. 获取mapper的代理对象
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
// 5. 执行正常的操作
// 5.1 查询全部
List<Employee> employees = mapper.findAll();
for(Employee employee : employees) {
System.out.println(employee);
}
// 5.2 新增
Employee employ = new Employee();
employ.setId("111");
employ.setEage("23");
employ.setEname("憨憨");
employ.setEmploy("程序员");
mapper.addEmployee(employ);
// 5.3 删除
Employee employ = new Employee();
employ.setId("111");
mapper.delEmployee(employ);
// 5.4 修改
Employee employ = new Employee();
employ.setId("2");
Employee employee = mapper.getEmployee(employ);
employee.setEname("王哈哈哈");
mapper.updateEmployee(employee);
// 6. 提交事务
session.commit();
// 7. 关闭资源
session.close();
} catch (Exception e) {
e.printStackTrace();
}
}
1.1 SqlMapConfig.xml 中配置的标签元素和顺序
- properties(属性)
- settings(全局配置参数)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境集合属性对象)
|–environment(环境子属性对象)
|–transactionManager(事务管理)
|–dataSource(数据源) - mappers(映射器)
1,3,8是重点标签
1.2 两种操作数据库的方式
1、通过 session 获取对应的 Mapper 接口的代理对象,然后通过该代理对象 调用对应的方法。(建议使用)
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.findAll();
2、通过 session 直接调用接口中的方法
List<User> users = session.selectList("findAll");
//findAll接口中的方法
(PS:接口和 mapper.xml 缺一不可)
2 缓存
应用程序和数据库交互的过程是一个相对比较耗时的过程。
缓存存在的意义:让应用程序减少对数据库的访问,提升程序运行效率
2.1 一级缓存
SQISession级别的缓存。在操作数据库时需要构造SqlSession 对象,在对象中有一个数据结构(HashMap) 用于存储缓存数据。不同的SqlSession 之间的缓存数据区域(HashMap) 是互相不影响的。默认是开启的
key:sql语句
value:获取的值
同一个SqlSession对象调用同一个< select>时,只有第一次访问数据库,之后把查询结果缓存到SqlSession缓存区(内存)中去。
缓存的是statement对象.(简单记忆必须是用一个是用一个< select>),在 myabtis 时一个< select>对应一个 statement 对象。
有效范围必须是同一个 SqlSession 对象。
一旦涉及数据改动(增删改),mybatis自动清除一级缓存,防止读取脏数据。
2.2 二级缓存
mapper级别的缓存。多个SqISession 去操作同一个mapper的sql 语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession 的。需要手动开启
有效范围:同一个 factory 内哪个 SqlSession 都可以获取。
1.在 SQLMapConfig.xml 设置二级缓存的总开关(< setting name=“cacheEnabled” value=“true”/>);
2.还要在具体的 mapper.xml 中开启二级缓存(< cache/>);
3.如果不写 readOnly=”true”需要把实体类序列化 = = = = 因为查询出的对象要被序列化后存入内存,所以需要实体类实现 Serializable 接口。< cache readOnly=” true”>< /cache >
4.要想二级缓存生效,必须提交事务。
当 SqlSession 对象 close()时或 commit()时会把 SqlSession 缓存的数据刷(flush)到 SqlSessionFactory 缓存区中。
刷新二级缓存:
数据改变(增删改);再开启一个 sqlSession3,当 sqlSession1 查询完成后,sqlSession3 执行一次插入操作,为了避免脏读会刷新缓存,然后再用 sqlSession2 进行查询,缓存中就没有数据。
事务隔离:https://blog.csdn.net/weixin_45044097/article/details/103037246
3 输入输出映射
数据库(下划线命名法),pojo(驼峰命名法)
数据库下划线命名转换为驼峰命名法:
< setting name=“mapUnderscoreToCamelCase” value=“true”/>
3.1 如何解析sql语句
Mybatis对于用户在XXMapper.xml文件中配置的sql解析主要分为2个时机:
静态sql:程序启动的时候解析
动态sql:用户进行查询等sql相关操作的时候解析
sql文本中包含${}参数占位符则为动态sql,否则为静态sql。 静态sql效率会比动态sql好。
加载核心配置文件,解析标签,sql,动态代理,加载到方法。。。。。。
面试题:Mybatis中的Dao接口和XML文件里的SQL是如何建立关系的?
http://www.mybatis.cn/archives/467.html
3.2 #{ }和${ }的区别
#{ }
表示一个占位符号(和传统jdbc中的?作用一致),可以实现preparedStatement 向占位符中设置值, 自动进行 java 类型和 jdbc 类型转换。可以接收简单类型值或 pojo 属性值。如果parameterType 传输单个简单类型值, #{}括号中可以是 value 或其它名称。在预编译的时候会把参数使用一个占位符?代替,进入数据库后会把?替换成具体的属性值,需要进行数据类型装换,能有效防止sql注入;
$ { }
表示拼接sql串通过,$ {}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值, ${}括号中只能是 value。
可能发生sql注入,因为在动态解析的时候会把这部分sql语句当做sql片段进行sql拼接而不会发生数据类型的装换,到数据库之后就会变成一个已经定型的sql语句了。
3.3 参数的传入
1.单参数传递
占位符的名字和参数名一致
2.多参数传递
-
传递对象(pojo):占位符的名字和pojo的属性名一致
-
传递map:占位符的名字和map的key一致
-
直接传递多参数:特殊占位符的名字注意: 允许的参数名 [arg1, arg0, param1, param2],如果有三个参数则为 arg3 或者param3…以此类推
注意参数arg1, arg0对应起来。
对应接口文件:
4. 注解的方式:自定义名字=====>比较常用
- @Param( value=”参数") 和 占位符一致
<insert id="insert">
insert into dept(id,deptName) values (#{id},#{deptName})
</insert>
接口中:
Integer insert(@Param(value=“id”)String id, @Param(value=“deptName”)String deptName)
map传出
下划线转驼峰;
结果映射:
注解的使用
还需要在 sqlMapConfig.xml 中配置一下 mapper 接口的路径:
parameterType 和 resultType
- parameterType:指定输入参数类型, mybatis 通过 ognl 从输入对象中获取参数值拼接在 sql 中。
- resultType:指定输出结果类型, mybatis 将 sql 查询结果的一行记录数据映射为 resultType 指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器 List 中。
4 动态sql
见下篇文章:
https://blog.csdn.net/weixin_45044097/article/details/103138976