引入mybatis后的代码结构
mapper.xml-->dao接口-->service-->Controller
Dao接口的实现类对象由sqlSession.getMapper(接口名.class)动态构建出来
什么是mybatis:
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录.
关于映射文件
总的配置文件
Configuration.xml: 是 mybatis 用来建立 sessionFactory 用的,里面主要包含了数据库连接相关东西,还有 java 类所对应的别名,比如 <typeAlias alias(别名)="User" type="com.yihaomen.mybatis.model.User"/> 这个别名非常重要,你在 具体的类的映射中,比如User.xml 中 resultType 就是对应这里的。要保持一致,当然这里的 resultType 还有另外单独的定义方式,后面再说。类的映射配置文件需要在这里注册
Mapper映射文件:里面主要是定义各种SQL 语句,以及这些语句的参数,以及要返回的类型等.
配置顺序:
在配置mybatis-config.xml时,其中的节点是有顺序的,配置顺序依次为:
properties/settings/typeAliases/typeHandlers/objectFactory/objectWrapperFactory/plugins/environments/databaseIdProvider/mappers
nameSpace
namespase有三种绑定方式,一般用绑定接口的方式。
命名:namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的。
在大型项目中,可能存在大量的SQL语句,这时候为每个SQL语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在MyBatis中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个SQL语句就成了定义在这个命名空间中的一个ID。只要我们能够保证每个命名空间中这个ID是唯一的,即使在不同映射文件中的语句ID相同,也不会再产生冲突了。
在mybatis中,映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。
当你的namespace绑定接口后,你可以不用写接口实现类,mybatis会通过该绑定自动
帮你找到对应要执行的SQL语句
假设定义了IArticeDAO接口
public interface IArticleDAO
{
List<Article> selectAllArticle();
}
对于映射文件如下:
<mapper namespace="IArticleDAO">
<select id="selectAllArticle" resultType="article">//article为Java类
SELECT t.* FROM T_article t WHERE t.flag = '1' ORDER BY t.createtime DESC
</select>
请注意接口中的方法与映射文件中的SQL语句的ID一一对应 。
则在代码中可以直接使用IArticeDAO面向接口编程而不需要再编写实现类。
别名的使用:
MyBatis中如果每次配置类名都要写全称也太不友好了,我们可以通过在主配置文件中配置别名,就不再需要指定完整的包名了。
用法:
自定义别名:
在SqlMapConfig.xml(MyBatis核心配置文件中的配置)中配置:
<typeAliases>
<!-- 定义单个类的别名,这里别名为user,在parameterType和resultType里面用的时候,不区分大小写,User,user,UsER,UseR都可以 -->
<typeAlias type="cn.domarvel.entity.User" alias="user"/>
<!-- 批量定义别名(常用),这里别名为类名User,在parameterType和resultType里面用的时候,不区分大小写,User,user,UsER,UseR都可以,
注意:
这里不支持通配符,比如:“*”,“_”,“?”
-->
<package name="cn.domarvel.entity"/>
</typeAliases>
但是如果每一个实体类都这样配置还是有点麻烦这时我们可以直接指定package的名字, mybatis会自动扫描指定包下面的javabean,并且默认设置一个别名,默认的名字为: javabean 的首字母小写的非限定类名来作为它的别名(其实别名是不去分大小写的)。也可在javabean 加上注解@Alias 来自定义别名, 例如: @Alias(student)
这样,在Mapper中我们就不用每次配置都写类的全名了,但是有一个例外,那就是namespace。
namespace属性
<typeAliases>
<package name="com.domain"/>
</typeAliases>
在MyBatis中,Mapper中的namespace用于绑定Dao接口的,即面向接口编程。
它的好处在于当使用了namespace之后就可以不用写接口实现类,业务逻辑会直接通过这个绑定寻找到相对应的SQL语句进行对应的数据处理
以接口的方式编程(即面向接口编程)
接口式编程,我们可以简单的理解为Mybatis为映射文件定义了一个代理接口,以后全部通过这个接口来和映射文件交互,而不再是使用以前方法。映射文件如何知道自己被哪个接口代理呢?这里就是通过名称空间来实现的,映射文件的名称空间再也不是随心所欲的定义的了,而是要使用代理接口的全限定名作为其名称空间。所谓全限定名,就是接口所在的包名加上接口名称。
// 01查看全部信息getMapper()接口类的方法名要和小配置的id一样
@Test
public void testSelectAll() {
SqlSession session = factory.openSession();
//用的是弱类型========实体类.小配置里面的Id名称============字符串
/*List<Dept> list = session.selectList("cn.happy.dao.IDeptDao.getAllDept");
for (Dept dept : list) {
System.out.println(dept.getDeptName());
}*/
// 用getMapper方法HIbernate帮我们在内存中代理出一个接口的实现类======相当于强类型
//mapper是一个实现类对象
IDeptDao mapper = session.getMapper(IDeptDao.class);
List<Dept> list = mapper.getAllDept();
for (Dept dept : list) {
System.out.println(dept.getDeptName());
}
优点:
- 调用方法明确,因为我们调用的是接口中的某个具体方法,而不再是通过一个字符串来指定执行映射文件中的某个SQL语句了
- 传入参数和返回值都不再是Object了,这样就可以在代码编写阶段确保传入的参数类型是正确的,也不再需要对返回值进行强类型转换了
- 最主要的一点,就是将来Mybatis遇到了Spring,更能发挥出接口式编程的强大潜力。
实现数据的增删改查
resultMap:
可以说是MyBatis的精华所在!
在深入ResultMap标签前,我们需要了解从SQL查询结果集到JavaBean或POJO实体的过程。
1. 通过JDBC查询得到ResultSet对象
2. 遍历ResultSet对象并将每行数据暂存到HashMap实例中,以结果集的字段名或字段别名为键,以字段值为值
3. 根据ResultMap标签的type属性通过反射实例化领域模型
4. 根据ResultMap标签的type属性和id、result等标签信息将HashMap中的键值对,填充到领域模型实例中并返回
不同的xml文件相互引用resultMap
利用命名空间+resultMapID就可以直接引用其他Mapper文件的resultMap,其中resultMap的column在本文件中也有用,也可以对应sql语句中的column别名。
对column(字段)和property(属性)的理解
Column对应数据库中的字段名,property对应Javabean的属性
Select相关属性:
select元素有很多属性(这里说用的比较多的):
id:命名空间唯一标识,可以被用来引用这条语句
parameterType:传入参数的类型
resultType:返回值类型(这里注意下集合类型,应该是集合可以包含的类型,不能是集合本身),重要:使用resultType或resultMap,但不能同时使用。
resultMap:命名引用外部的resultMap,其名称要和外部的resultMap元素的ID名称一致,用于映射其结果到实体类指定对象中。
实例:
<select id="getStudent" resultMap="getStudentRM">
SELECT ID, Name, Age
FROM TStudent
</select>
<resultMap id="getStudentRM" type="EStudnet">
<id property="id" column="ID"/>
<result property="studentName" column="Name"/>
<result property="studentAge" column="Age"/>
</resultMap>
若数据库中的字段与javabean中的属性相同,则:
<resultMap type="com.test" id="testResultMap">
</resultMap>
<select id="selectList" resultMap="testResultMap">
select * from test1
</select>
子元素说明:
id元素 ,用于设置主键字段与领域模型属性的映射关系
result元素 ,用于设置普通字段与领域模型属性的映射关系
那么什么时候我们知道使用resultMap,什么时候又使用resultType呢?
①当去select一张表时,可以使用resultType,这些情况下,MyBatis会在幕后自动创建一个ReusltMap,基于属性名来映射到JavaBean属性上
②所以在使用resultMap时,就必须要写上resultMap相对应的xml
③为了方便我们开发出错,在没有特别要求的情况下,column名可以完全和property名称一致,否则当我们没有对应上的时候,数据库匹配不到,会将某某参数值变为大写,导致我们本来获取小写的参数名,结果没有获取到,后台报错,得不偿失啊!
Mapper标签详解:
https://blog.csdn.net/Marvel__Dead/article/details/69265316
目录结构
Web项目中接口和接口的配置文件在同一个包中
Maven项目中:
为了实现在maven默认环境下打包时,Mybatis的接口和mapper文件在同一包中,可以通过将接口文件放在src/main/java某个包中,而在src/main/resources目录中建立同样的包,这是一种约定优于配置的方式,这样在maven打包的时候就会将src/main/java和src/main/resources相同包下的文件合并到同一包中。
MyBatisUtil:
package me.gacl.util;
import java.io.InputStream;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
/**
* 获取SqlSessionFactory
* @return SqlSessionFactory
*/
public static SqlSessionFactory getSqlSessionFactory() {//static 加载类的时候一并加载进去
String resource = "conf.xml";
//加载文件
InputStream is = MyBatisUtil.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
return factory;
}
/**
* 获取SqlSession
* @return SqlSession
*/
public static SqlSession getSqlSession() {
return getSqlSessionFactory().openSession();
}
/**
* 获取SqlSession
* @param isAutoCommit
* true 表示创建的SqlSession对象在执行完SQL之后会自动提交事务
* false 表示创建的SqlSession对象在执行完SQL之后不会自动提交事务,这时就需要我们手动调用sqlSession.commit()提交事务
* @return SqlSession
*/
public static SqlSession getSqlSession(boolean isAutoCommit) {
return getSqlSessionFactory().openSession(isAutoCommit);
}
}
动态SQL语句:
If语句:
test属性中做常规判断,里面不能写 < 和 > ,也不能用&&,可以用and、 or 、||
| Test属性中 | SQL语句中 |
gt | > | > |
gte | >= | >= |
lt | < | < |
lte | <= | <= |
模糊查询:
MySql中要用concat
and name like concat('%',#{name},'%')
引入参数:
一个参数时:(mybatis会自动识别)
若parameterType中为int、string等Java固有类型,即传入的参数为非JavaBean类,则写xml文件时应用_parameter代替原参数。
多个参数时:
@Select("select * from tb_sender where username=#{username} and password = #{password}")
Sender selectSenderByUsernameAndPassword(@Param("username") String username,@Param("password") String password);
MySql数据库级联操作:
MySQL支持外键的存储引擎只有InnoDB,在创建外键的时候,要求父表必须有对应的索引,子表在创建外键的时候也会自动创建对应的索引。在创建索引的时候,可以指定在删除、更新父表时,对子表进行的相应操作,包括RESTRICT、NO ACTION、SET NULL和CASCADE。其中RESTRICT和NO ACTION相同,是指在子表有关联记录的情况下父表不能更新;CASCADE表示父表在更新或者删除时,更新或者删除子表对应记录;SET NULL则是表示父表在更新或者删除的时候,子表的对应字段被SET NULL。
关联查询
一对一:
一对多:
多对多: