MyBatis框架
学习路线:javase,javaweb ssm框架的第一堂课。
SSM框架:MyBatis,Spring,SpringMVC,SSM项目
微服务框架
互联网分布式技术
绪论 代理模式
什么是代理模式?
无法访问目标对象,通过代理对象进行访问,而且增强式的访问,适合进行业务扩展。
- ==代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。==在某些情况下,一个对象不适合或者不能字何解引用另一个对象,而代理对象可以在客户和目标对象之间起到中介的作用。
- 使用代理对象,是为了不修改目标对象的基础上,增强主业务逻辑。客户类真正的想要访问的对象是目标对象,但客户类真真可以访问的对象是代理对象。
- 客户类对目标对象的访问时通过访问代理对象来实现的,当然,代理类与目标类要实现同一个接口。
- 目标对象不可访问,通过代理对象增强功能访问。
代理模式的作用
- 控制目标对象的访问
- 增强功能
代理模式的分类
- 静态代理
- 动态代理
- JDK动态代理
- CGLib动态代理(子类代理)
静态代理
静态代理是代理模式的一种。
具备以下特点
- 目标对象和代理对象实现同一个业务接口
- 目标对象必须实现接口
- 代理对象在程序运行之前就已经存在
- 能顾灵活的进行目标对象的且胡安,却无法进行功能的灵活处理(使用动态代理解决这个问题)
面向接口编程(####)
- 类中的成员变量设计为接口,
- 方法的形参设计为接口,
- 方法的返回值设计为接口,
- 调用时接口指向实现类
动态代理
代理对象在程序运行的过程中动态在内存中构建可以灵活的进行业务功能的切换。
JDK动态代理
- 目标对象必须实现业务接口
- 代理对象必须实现业务接口
- 动态代理的对象在程序运行前不存在,在程序运行时动态的在内存中构建。
- 动态代理灵活的进行业务功能的切换。
- 本类中的方法(非接口)中的方法不能被代理。
JDK动态代理用到的类和接口
-
使用现成的工具类万恒JDK动态实现。
-
Proxy类:java.lang.reflect.Proxy包下面的类,有一个方法Proxy.newProxyInstance();专门用来生成动态代理对象。
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) { Objects.requireNonNull(h); @SuppressWarnings("removal") final Class<?> caller = System.getSecurityManager() == null ? null : Reflection.getCallerClass(); /* * Look up or generate the designated proxy class and its constructor. */ Constructor<?> cons = getProxyConstructor(caller, loader, interfaces); return newProxyInstance(caller, cons, h); }
ClassLoader:类加载器;Class<?>泛型,目标对象实现的所有接口。InvocationHandler就类似于Agent(代理类的功能),代理的功能和目标对象的业务功能调用在这。
-
Method类:反射用的类,用来进行目标对象的方法的反射调用。method对西安给借助我们正在调用的方法sing(),show()等。method.invoke();== = ==>手工调用目标方法,sing(),show();
-
InvocationHandler接口:它是实现代理和业务功能的,我们在调用时使用匿名内部类实现。
ClassLoader loader, //类加载器,完成目标对象的加载 target.getClass().getClassLoader(), Class<?>[] interfaces, //目标对象实现的所有接口 target.getClass().getInterfaces(), InvocationHandler h //实现代理和业务功能的接口,我们传入的时匿名内部实现 new InvocationHandler(){ @Ocerride public Object invoke( //创建代理对象 Object proxy, //method就是目标方法sing(),show() Method method, //目标方法的参数 Object[] args) throws Throwable{ //return null; //代理功能 System.out.println("预定时间。。。。。。。。。"); //代理功能 System.out.println("预定地点。。。。。。。。。"); //主业务功能 //target。sing()这样还是写死了,所以不能这样写 Object invoke = method.invoke(target, args); //代理功能 System.out.println("结算费用。。。。。。。。。"); return invoke;//切记,这是目标方法的返回值。 } }
-
CGLib动态代理
-
又称为子类,通过动态的在内存中构建子类对象,重写父类方法及逆行你个代理功能的增强。
-
如果目标对象没有是西安接口,则只能通过CGLib子类代理来进行功能增强。
-
子类代理是对象字节码框架ASM来实现的。(不要求写,不是JDK自带的,导包,Spring框架的包即可)
-
子类重写父类的方法,完成功能增强,
-
CGLib使用ASM来转换字节码并生成新的类。不鼓励直接使用ASM。==
-
被代理的类不能是final,final修饰方法,方法不能被重写,修饰类,断子绝孙类,不允许扩展。被代理的方法不能被static/final,静态方法不能被代理。
-
Object和Service区别:接口更加灵活,传入的是接口的实现类,如果是Object,任何类型都可以传入,需要判断类型,之后转换,才能点使用方法。
-
JDK代理,使用的是接口。invocation Handler,增强了代理的功能。
-
public Object getProxyInstance(){ //使用工具类 Enhancer en = new Enhancer(); //设置父类 en.setSuperclass(target.getClass()); //设置回调函数 en.setCallback(this); //创建子类(代理)对象 return en.create(); =====>返回的是子类代理对象 }
23种设计模式之一:动态代理;
静态代理:要求目标对象和代理对象实现同一个业务接口。代理对象的各种的核心功能是由目标对象来完成,代理对象负责增强功能。
Proxy负责生成代理对象
Method目标方法的回调用,使用反射机制
IncvocationHandler 增强代码功能,外部目标对象方法被调用时,此接口实现类被执行。
第一章 框架结构
1.1,什么是三层架构
-
在项目开发中,遵循的一种形式模式
1)界面层:用来接收客户端的输入,调用业务逻辑层进行功能处理,返回结果给客户端,过去的servlet就是界面层的功能。Servlet中什么也不能干咯
2)业务逻辑层:用来进行整个项目的业务逻辑处理,向上为界面层提供处理结果,向下向数据访问层要数据。
3)数据访问层:专门用来进行数据库的增删改查操作,向上为业务逻辑层提供数据。
-
各层之间的调用顺序时固定的,不允许跨层访问。
界面层<——>业务逻辑层<——>数据访问层
-
生活中的三层架构:服务员<——>厨师<——>采购员
界面层<——>业务逻辑层<——>数据访问层
-
开发项目中就是这样的逻辑,不允许跨层访问。如果跨层访问,就把厨师腿打断。
1.2,三层架构的优点
- 结构清晰,耦合度低,各层分工明确。
- 可维护性高,可扩展性高
- 有利于标准化
- 开发人员可以只关注整个结构中的其中某一层的功能实现
- 有利于各层逻辑的复用
1.3,常用框架SSM:
- Spring:整合其他框架的框架。核心是IOC(控制反转)和AOP(面向切面编程),它由20多个模块构成。在很多领域都提供了很好的解决方案,是一个大佬级别的存在
- SpringMVC:Sprng家族的一员,专门用来优化控制器的(Servlet)。提供了极简单的数据提交,数据携带,页面跳转等功能。
- MyBatis:是持久化层的框架,专门用来进行数据库访问的优化,专注于SQL语句,极大的简化了JDBC的访问。
1.4,什么是框架:
- 是一个半成品软件,将所有的公共的,重复的功能解决掉,帮助程序员快速高效的及进行开发,它是可以复用的,可扩展的。
第二章 MyBatis框架快速入门
2.1,什么是MyBatis框架
- MyBatis是apache的一个开源项目,iBatis,2010年改名,
- 完成数据访问层的优化,专注于SQL语句,简化了过去JDBC繁琐的访问机制。
2.2,添加框架的步骤
- 添加依赖
- 添加配置文件
具体步骤
-
新建库建表
-
新建maven项目,选quickstart模板
-
修改目录,添加缺失的目录,修改目录属性
-
修改pom.xml文件,添加MyBatis的依赖,添加mysql依赖
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.10</version> </dependency> <!--添加mysql的依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.0.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies>
-
修改pom.xml文件,添加资源文件指定
<!--必须要添加资源文件的指定--> <!--为了将所有文件夹中的内容添加到编译后的内容中--> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> </resource> </resources> </build>
-
IDEA中添加数据库的可视化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bcAICTCu-1661752772169)(C:\Users\29933\AppData\Roaming\Typora\typora-user-images\image-20220819151246342.png)]
-
添加JDBC.properties属性文件(数据库的配置文件)
jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/bjpowernode?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=123456
-
添加SqlMapConfig.xml文件,MyBatis的核心配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mubatis.org/dtd/mybatis-3-config.dtd"> <!--需要注意这个文件创建的时候不是创建xml文件而是直接创建file文件,也就是直接创建file文件--> <configuration> <!--读取属性文件(jdbc.properties) 属性: resources:从resources目录下找指定名称的文件加载 url:使用绝对路径加载属性配置文件 --> <properties resource="jdbc.properties"></properties> <!--配置数据库的环境变量(数据库连接配置) 属性: default:使用下面的environment标签的id属性进行指定配置--> <environments default="development"> <!--开发时,使用的公司的数据库的配置 属性: id:提供给environment的default属性使用 --> <environment id="development"> <!--配置事务管理器 type:指定事务管理方式 JDBC:采用JDBC的方式进行事务的管理,事务的控制交给程序员 MANAGED:由容器管理事务, --> <transactionManager type="JDBC"></transactionManager> <!--dataSource:配置数据源 type:指定不同的配置方式 JNDI:java命名目录接口,在服务器端进行数据库连接池的管理(不常用) POOLED:使用数据库连接池, UNPOOLED:不使用数据库连接池--> <dataSource type="POOLED"></dataSource> </environment> <!-- <!–上线时,使用的服务器的数据库的配置–> <environment id="home"> <transactionManager type=""></transactionManager> <dataSource type=""></dataSource> </environment> <!–开发时,使用的本机的数据库的配置–> <environment id="localhost"> <transactionManager type="test"></transactionManager> <dataSource type=""></dataSource> </environment>--> </environments> <!--注册mapper.xml文件--> </configuration>
-
添加实体类Student,用来封装数据
package com.gh.MBDemo.pojo; public class Student { private Integer id ; private String name; private String email; private Integer age; public Student() { } public Student(Integer id, String name, String email, Integer age) { this.id = id; this.name = name; this.email = email; this.age = age; } public Student(String name, String email, Integer age) { this.name = name; this.email = email; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", email='" + email + '\'' + ", age=" + age + '}';}}
-
添加完成学生表的增删改查的功能的StudentMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mubatis.org/dtd/mybatis-3-mapper.dtd"> <!-- mapper:是整个文件的大标签,用来开始和结束xml文件 属性: namespace:指定命名空间(相当于包名),用来区分不同的mapper --> <mapper namespace="zar"> <!--完成查询全部学生的信息的功能 resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型 resultType="com.gh.MBDemo.pojo.Student"必须要这么写,要加上包名, parameterType:如果有参数,则通过它来指定参数的类型 --> <select id="getAll" resultType="com.gh.MBDemo.pojo.Student"> select id,name,email,age from student </select> <!--按主键id查询学生信息 Student getById(Integer id) 这是有参数的所以需要设置parameterType这个值,注意有别名机制,左边是写mapper文件用的名称,右边是写java程序对应的变量--> <select id="getById" parameterType="int" resultType="com.gh.MBDemo.pojo.Student"> select id,name,email,age from student where id=#{id} </select> <!--按学生名称模糊查询 List<Student> getByName(String name); --> <select id="getByName" parameterType="string" resultType="com.gh.MBDemo.pojo.Student"> select id,name,email,age from student where name like '%${name}%' </select> <!-- 增加学生 int Student(Student,stu); private Integer id ; private String name; private String email; private Integer age; --> <insert id="c" parameterType="com.gh.MBDemo.pojo.Student"> insert into student (name,email,age) values(#{name},#{email},#{age}) </insert> <!--删除学生 按照主键删除学生--> <delete id="delete" parameterType="int" > delete from student where id =#{id} </delete> <!--更新学生 --> <update id="update" parameterType="com.gh.MBDemo.pojo.Student"> update student set name=#{name},email=#{email},age=#{age} where id=#{id} </update> </mapper>
- MyBatis提供了最优配置,不需要我们再配置。
MyBatis对象分析
-
Resources类:就是解析SqlMapConfig.xml文件,创建出响应的对象
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
-
SqlSessionFactory接口:拿到接口的实现类去操作。查看接口本接口的子接口及实现类:CTRL+H
DefaultSqlSessionFactory factory = new SqlSessionFactoryBuild().build();//建造者模式的类
-
SqlSession接口:DefaultSqlSession实现类;
-
为实体类注册别名
-
单个注册
<typeAliases> <typeAlias type="com.gh.MBDemo.pojo.Student" alias="student"></typeAlias> </typeAliases> <!--弊端 如果有很多实体类,这样代码就太多了 -->
-
批量注册
<!--批量注册别名 别名是类名的驼峰明名法--> <package name="com.gh.MBDemo.pojo"/>
-
-
设置日志输出当前底层的结果。
<!--设置日志输出底层代码的执行结果--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
第三章 动态代理(重点)
3.1,动态代理开发规范
- 为什么需要动态代理?没法用接口指向实现类。因为无法在业务逻辑层访问xml文件的功能,使用动态代理就可以解决这个问题,在业务逻辑层依然使用接口调用xml文件中的功能,这个功能由动态代理对象代理出来。
- 存在的意义:在三层架构中,业务逻辑层要通过接口访问数据访问层的功能,动态代理可以实现。
- 动态代理的实现规范
- UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下。
- UsersMapper.xml文件与UsersMapper.java的文件名必须一致,后缀不管。
- UsersMapper.xml文件中标签的id值与UsersMapper.java的接口文件中的方法名必须完全一致。
- UsersMapper.xml文件中标签的属性值与UsersMapper.java的接口中方法的参数必须一致。
- UsersMapper.xml文件中标签的属性值与UsersMapper.java的接口中方法的参数必须一致。
- UsersMapper.xml文件中标签的属性必须是接口的完全限定名称。com.gh.mapper.UsersMapper;
- 在sqlMapperConfig.xml文件中注册Mapper文件时,使用class=接口的完全限定名com.gh.mapper.UsersMapper;
3.2,动态代理的访问步骤
- 新建User表
- 新建maven工程,刷新可视化
- 修改目录
- 修改pom.xml文件,添加依赖
- 添加jdbc.properties文件到resoures目录下
- 添加sqlMapConfig.xml文件
- 添加实体类
- 添加Mapper的 文件夹,新建UserMapper接口
- 在mapper的文件夹下面,新建UserMapper.xml文件,完成增删改查功能。
- 添加测试类,功能测试。
3.3 #{}和${}
-
#{} :是对非字符串拼接的参数的占位符。如果入参是简单数据类型,#{}里可以任意写,但是如果入参是对象类型,则#{}里必须是对象的成员变量的名称,#{}可以有效地防止sql注入。
-
${} :主要是针对字符串拼接替换,如果入参是基本数据类型,${}里必须是value,但是如果入参是对象类型,则$${}里必须是对象的成员变量的名称,${}还可以替换列名和表明,存在sql注入风险,尽量少用。
-
#{} 演示:用来参数的占位,传参大部分使用这种,它的底层使用的是PreparedStatement对象,是安全的数据库访问,防止sql注入。
-
如果parameterType的类型是简单类型(8种基本数据类型和封装类型),则#{参数}里面的参数随便写
<select id="getByName" parameterType="string" resultType="users"> ====>入参是基本数据类型 select id,username,birthday,sex,address from t_user where username like '%${name}%' </select>
-
parameterType的类型是实体类的类型,则#{参数},参数只能是类中成员比那连过的值,并且区分大小写。
<insert id="insert" parameterType="users"> =====>入参是实体类 insert into t_user (username,birthday,sex,address) values (#{userName},#{birthday},#{sex},#{address}) </insert>
-
-
${},字符串拼接,或者叫做字符串替换
-
字符串拼接,一般用于模糊查询种,建议少用,因为有sql注入的风险
-
也分两种情况
-
如果parameterType的类型是简单类型,则${}里面随便写,但是分版本,如果是3.5.1及以下的版本,只写value。
<select id="getByName" parameterType="string" resultType="users"> select id,username,birthday,sex,address from t_user where username like '%${name}%' </select>
-
如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称。(现在已经很少使用这种)
-
优化后的模糊查询,以后模糊查询都是用这种方式。
<!-- 优化后的模糊查询 //优化后的模糊查询 List<Users> getByNameGood(String name); concat('%',#{name},'%') 采用函数的方式进行字符串的拼接。 --> <select id="getByNameGood" parameterType="string" resultType="users"> select id,username,birthday,sex,address from t_user where username like concat('%',#{name},'%') </select>
-
-
字符串替换
-
需求:模糊地址或用户名查询。
<!-- //模糊用户名和地址查询 List<Users> getByNameOrAddress(String columnName,String columnValue); 如果参数超过一个,则parameterType不写。 --> <select id="getByNameOrAddress" resultType="users"> select id,username,birthday,sex,address from t_user where ${columnName} like concat('%',#{columnValue},'%') </select>
//模糊用户名和地址查询 List<Users> getByNameOrAddress( @Param("columnName") String columnName, @Param("columnValue") String columnValue);
@Test public void TestGetByNameOrAddress(){ List<Users> list = usersMapper.getByNameOrAddress("address","北"); list.forEach(users -> System.out.println(users)); }
-
字符串替换的时候想到用${}去干活,别的时候尽量考虑#{}符号,这个会防止sql注入的风险。
-
-
-
返回主键值
在插入语句结束后,返回自增的主键值到入参的users对象的id属性中
<insert id="insert" parameterType="users"> <selectKey keyProperty="id" resultType="int" order="AFTER"> select last_insert_id(); </selectKey> insert into t_user (username,birthday,sex,address) values (#{userName},#{birthday},#{sex},#{address}) </insert>
- 参数详解
- keyProperty :users对象的哪个属性来接返回的主键。
- resultType :返回的主键的类型
- order :在插入预计执行前,还是执行后返回之间的值。(插入语句执行的顺序和取值的顺序)
- 参数详解
-
提供了一个uuid:全球唯一字符串,由36个字母数字组成。
public void TestUUid(){ UUID uuid = UUID.randomUUID(); System.out.println(uuid.toString().replace("-","").substring(10,20)); } // 5b41409005
第四章 动态sql(重点)
4.1 动态Sql概念
4.2 什么是动态sql?
可以定义代码片段,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更为简单。
- :用来定义代码片段,可以将所有的列名,或复杂的条件定义为代码片段,供使用时调用。
- :用来引用sql定义的代码片段。
- :进行条件判断,判断的语句写在test属性中。
- :进行多条件拼接,在查询,删除,更新中使用。
- :有选择的进行更新处理,至少更新一列。
- :增删改查都可以使用,批量使用。用来进行循环遍历,完成寻呼那条件查询,批量删除,增加,更新都可以用。
- collection :用来指定入参的类型,如果时List集合,则为list,如果是Map,则为map,如果是数组,则为array。
- item:每次循环遍历出来的值或者对象。
- separator:多个值或者对象或语句之间的分隔符
- open:整个循环外面的前括号
- close:整个循环外面的后括号
<!--定义代码片段-->
<sql id="allColumns">
id,username,birthday,sex,address
</sql>
<select id="GetAllColumn">
select <include refid="allColumns"></include>
from t_users
</select>
//按照指定的条件,进行多条件查询
List<Users> getByCondition(Users users);
-->
<select id="getByCondition" resultType="users" parameterType="users">
select <include refid="allColumns"></include>
from t_user
<where>
<if test="userName != null and userName != ''">
and username like concat('%',#{userName},'%')
</if>
<if test="birthday != null">
and birthday = #{birthday}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
<if test="address != null and address != ''">
and address like concat('%',#{address},'%')
</if>
</where>
</select>
<!--
//有选择的更新
int updateBySet(Users users);
-->
<update id="updateBySet" parameterType="users">
update t_user
<set>
<if test="userName != null and userName != ''">
username = #{userName},
</if>
<if test="birthday != null">
birthday = #{birthday},
</if>
<if test="sex != null and sex != ''">
sex = #{sex},
</if>
<if test="address != null and address != ''">
address = #{address},
</if>
</set>
where id = #{id}
</update>
<!--
//查询多个指定id的用户信息,
List<Users> getByIds(Integer []arr);
简单类型的传参不用写,但是实体类的就必须写上。
-->
<select id="getByIds" resultType="users">
select <include refid="allColumns"></include>
from t_user
where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
<!--
//批量删除
int deleteBatch(Integer integer);
-->
<delete id="deleteBatch">
delete from t_user
where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<!--
//批量增加
int insertBatch(List<Users> users);
-->
<insert id="insertBatch">
insert into t_user(username,birthday,sex,address)
values
<foreach collection="list" item="u" separator=",">
(#{u.userName},#{u.birthday},#{u.sex},#{u.address})
</foreach>
</insert>
4.3 指点参数位置:
- 如果入参是多个,可以通过指定参数位置进行传参,是实体类包含不住的条件,实体类只能封装住成员变量的条件,如果某个成员变量要有区间范围内的判断,或者有两个值进行处理,则实体类保不住。
- 例如,查询指定日期范围内的用户信息。
4.4 入参是map(重点)
-
如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更见明确。
<!-- 入参是map //入参是map(实体类封装不了的时候使用) List<Users> GetByMap(Map map); 只有实体类的类型必须要写,别的都可以不用写 #{birthdayBegin}:使用的是map中的key和value #{birthdayEnd}:使用的是map中的key和value --> <select id="GetByMap" resultType="users"> select <include refid="allColumns"></include> from t_user where birthday between #{birthdayBegin} and #{birthdayEnd} </select> <!-- @Test public void TestGetByMap() throws ParseException { Date begin = simpleDateFormat.parse("1999-01-01"); Date end = simpleDateFormat.parse("2022-01-19"); Map map = new HashMap<>(); map.put("birthdayBegin",begin); map.put("birthdayEnd",end); List<Users> list = usersMapper.GetByMap(map); list.forEach(users -> System.out.println(users)); } -->
4.5 返回值是map
-
返回值是map的适用场景,如果的数据不能使用对象来封装,可能查询的数据来自多张表中的某些列,这种情况下,使用map但是map的返回方式破坏了对象的封装,返回来的数据是一个一个单的数据,之间不相关,map使用表中的列名或别名作为健名进行返回数据。
-
map封装返回值是一行:
如果返回的数据实体类无法包含,可以使用map返回多张表中的若干数据,返回后这些数据之间没有任何关系,就是Object类型。返回的map的key就是列名或者别名。
4.6 列名与类中成员变量名称不一致
-
使用列的别名
-
使用别名解决此问题
-
<select id="getAll" resultMap="book"> select bookid id,bookname name from book </select>
-
-
使用标签进行映射
- 可以手工定义映射
第五章 表与表的关联关系(难点)
5.1 一对多
- 关联关系是有方向的,一个老师可以教多个学生。多个学生只有一个老师。站在老师方,就是一对多,站在学生方就是多对一。
- 客户和订单就是典型的一对多关联关系,一个客户名下可以有多个订单。客户表是一方,订单表是多方。
- 使用一对多的关联关系,可以满足查询客户的同时查询该客户的所有订单信息。
- 两张表的关联查询操作:等值匹配,左外连接,inner join,等值匹配,left join左表为主,right join,右表为主。左关联,右外连接。一对多的关联查询。
5.2 多对一:多个学生由一个老师授课。
-
站在订单,插寻客户。
-
订单和客户就是多对一的关联。查询订单的同时,将客户信息查询出来。
-
订单是多方,会持有一方的对象。
-
关联下此顶顶那的客户信息。
select o.id oid,ordernum,orderprice,cuntomer_id ,c.id cid ,name,age from orders o inner join cuntomer c on cudtomer_id = orders_id
5.3 一对一:一个学生对应一个老师。
- 班级的信息,老师这个对象放在这里,当查询老师的时候查询出班级的信息。
5.4 多对多:每一个车位都可以停任何一辆车。
第六章 事务
一套事务,如果成功,全部成功,如果失败全部失败。原子性,一致性,隔离性,持久性
-
多个操作同时完成,或同时失败称为事务处理。
-
事务的四个特性
- 一致性 2.持久性 3.原子性 4.隔离性
-
下订单业务
- 订单表中完成增加一条记录的操作。
- 订单明细表中完成N条记录的增加。
- 商品数据更新(减少)
- 购物车中已支付商品减少
- 用户积分堆积。
-
在MyBatis框架中设置事务
<transactionManager type="JDBC"></transactionManager> ====》程序员自己控制处理的提交和回滚 commit;提交事务
-
也可以设置为自动提交
- sqlSession = factory.openSession(); ====》为空,默认是手工提交事务,设置为false,也是手工提交事务,如果设置为true,则为自动提交。
- sqlSession = facoory.Session(true);==>设置为自动提交。在增删改之后不需要commit,会自动给你提交了。
第七章 缓存(面试的点)
默认开启一级缓存,二次查询的数据不用再去数据库查询,直接从硬盘上拿数据,硬盘上拿数据的效率远远高于从数据库中拿的效率
缓存概念:
- MyBatis框架提供两级缓存,一级缓存和二级缓存,默认开启以及缓存。
- 缓存就是为了提高查询的效率。
- 使用缓存后查询的流程。
- 先去缓存查;如果没有执行2,如果有直接返回。
- 进行数据库访问;
- 将数据放到缓存中;
- 将数据从缓存回到客户端。
- 下次再次查询的时候直接从缓存中拿到即可。
- 如果数据库中发生了改变,就清空缓存即可。
- 一级缓存:使用的是sqlSession的作用域,同一份SqlSession共享一级缓存的数据。
- 二级缓存:使用的是Mapper的作用与,不同的
第八章 什么是ORM
对象关系映射:编写程序的时候,以面向对象的方式处理数据,保存数据的时候,却以关系型数据库的方式存储数据
处理数据的时候以对象处理,保存的时候按照关系型数据库的形式保存。