mybatis笔记

mybatis—-我的整理

2025.3.10刷完,历时6天。

我对mybatis框架的理解

学习框架一定要知道什么是框架,他有什么作用。

框架就是一个项目或者应用的半成品,已经有人给你实现了一部分基础的功能,你在这个基础上进行具体项目功能的开发,实现的部分功能通过集成第三方技术或者框架团队自己写的技术,例如,数据源是集成的第三方数据源,该技术实现连接数据库的功能,动态sql技术是开发团队自己写的技术,该技术实现各种查询功能;表数据和实体类自动映射技术,开发团队写的。总体来说,框架就是集成了和设计了很多技术,这些结束实现了部分功能,java程序员可以直接使用实现的这些功能去具体的业务开发,同时这些创新的技术实现原来相同功能的前提下,比原来的方法简单方便高效了许多。像原来的sql拼接实现查询改为动态sql实现查询;遍历resultset结果集,在结果集中,使用setter方法赋值给实体类实现表数据和实体类的映射改为自动映射技术。

框架主要体现在“实现部分功能”+“简化原先复杂操作”。

image-20250310155905624

  1. mybatis来说,实现部分功能是指这个框架里面集成了数据库连接池,事务管理等之前用过的技术或者新创新的技术来实现具体的功能。连接池,事务就像像框架中建好的电线,水管可以直接使用它们的功能。
  2. 简化原先复杂操作是指框架中的技术可以实现原先的功能的同时简化复杂的操作,相当于创新了。不用向原来jdbc一样手动加载驱动,重复写获得连接,保存sql,获得结果集,遍历结果集赋值的重复代码,mybatis自动映射。对于之前用数据库连接池时候,不用重复在不同dao层获取数据库连接池的连接对象,不用每个方法都编写sql语句。
  3. image-20250310150117405

1 动态SQL

1.1 主要的标签

关键理解点:

1.标签

的存在是为了判断你输入的属性是否为null或者为空字符串,如果不加这个if标签,一旦你输入的一个属性为空或者空字符串,这条sql语句查询结果就有误,加上后,可以判断为空或者空字符串就会不执行这个,根据其他的判断结果。

2.但是注意if标签前面在不加where 1=1情况下,第一个if标签的内容必须不为空,否则结果就会where后面直接跟and,sql语句错误,但是and后面的为空没有事,不会出现错误。

3.标签

改善第2点的where 1=1.用标签后,自动去掉and并生成关键字where,不错。

4.标签

改善标签的后面有and或者or的情况无法去掉的问题。

5.choose,when,otherwise标签

快速明确:

1.choose里面包含when和otherwise

2.when相当于if。。。else if。。。else if,至少有一个。otherwise相当于else,最多有一个。

3.choose使用的时候前面还是要加where标签生成where关键字,然后他与where和trim不同的是,他的里面只有一个条件成立。

6.标签

作用主要是批量删除和批量添加的效果,通过遍历来实现。

1.2 动态sql和java中写sql区别

mybatis里面直接写死sql可以不用拼接字符串,但一般适用于简单的固定查询,业务里面还是要用动态sql。

image-20250312205410649

2 各种查询功能

关键点理解:

1.接口方法返回值是单个对象或者多个对象用集合接收。

2.如何解决字段名和属性名不一致问题。

3.如何解决一对多,多对一映射的查询问题。

2.1 参数的几种类型

1.mapper接口方法参数是单个字面量类型

  • sql语句中的#{}里面可以是任何名称。都可以获取方法中的参数值。

2.mapper接口方法参数是多个时

mybatis会自动把这些参数放到一个map集合里面,以三种方式存储。(这三点的先后顺序一定分清,从小到大按的是参数的顺序)sql语句中的#{}里面的名称:

  • 以arg0,arg1为键,以参数为值。
  • 以param1,param2为键,以参数为值。
  • 以arg0,param2为键或者param1,arg1为键,参数为值

3.mapper接口的方法参数是多个时,可以手动将多个参数放到map集合

多个参数放到map集合里面时候,测试类里面需要new一个hashmap,方法中的每个参数是一个键值对的值,自己在测试类的hashmap中定义键,参数为值,sql语句中#{}里面引用的名称就是自己定义的键。跟第二种一样

4.mapper接口方法参数是实体类类型的参数
(属性不是简单的实体类的成员变量,是setter和getter去掉set和get后首字母变为小写的名字才是属性,因为以后可能遇到没有成员变量,但是有set和get方法的属性)

  • sql语句中#{}里面的名称直接用属性名。

5.以@param注解的方式命名参数

  • 以@param的值为键,参数为值
  • {}里面名称是@param的值。

6.mapper接口的方法参数是数组

mybatis会以array,~~arg0为键,数组参数为值存在map集合中。

这要分两种情况:

(1)用foreach遍历的时候,collection的值就是array或者arg0,item是数组或者集合中遍历的元素别名可以自定义。#{}里面的名称和其一致。

(2)不遍历时候,#{}里面的名称是array[索引]或者arg0[索引]

7.mapper接口的方法参数是list集合

mybatis以collection,arg0,list为键

3 相关问题

3.1 idea中模块问题

idea中创建项目分为两种情况:

  1. 直接创建一个项目,该项目默认有一个子模块,子模块名字默认与项目同名。这时候该项目自带一个模块。适合单体项目开发。
    • 如果想要加模块右键点击项目名->new moudle根据parent选择新建的模块与默认模块是否同级。一般多模块用第二种方式创建,第一种我认为结构不清晰。
  2. 创建一个空项目,然后在这个空项目中添加多个子模块的形式。适合多模块开发。不过建的是一个空项目,需要单独配置maven。

3.2 archetype骨架

3.2.1 误添加骨架如何删除?

C:\Users\lenovo\AppData\Local\JetBrains\IntelliJIdea2020.1\Maven\Indices这个路径下有一个Userarchetypes.xml文件删除就可以了,重启idea骨架面板中就没有了。

注意:创建maven项目时,如果不勾选create from archetypes->点击对应骨架的话,默认是空的maven项目没有任何骨架。

4 缓存

一级缓存:sqlsession级别

二级缓存:sqlsessionfacory级别。

也可以整合第三发缓存:ehcache。

5 逆向工程

简单说:

1.将逆向工程的坐标导入到pom中,加载后点击该插件就可以根据表自动生成mapper接口和映射文件,非常强大。

2.主要分为2个:

  • 简单版:点击该插件一次,生成不带条件的crud
  • 豪华版:删除之前生成的,再点击一次,生成待条件的和不带条件的crud。

6 分页插件

1.同样需要导入分页插件的坐标,然后配置一些文件,实现数据的导航分页,用到细雪。

7 占位符和sql注入问题

7.1 什么是sql注入问题?

SQL注入问题先了解一下:

字符串拼接是指多个字符串拼接在一起,+号的左右算作一个字符串,目的是把username和password动态的值拼接到固定的字符串模板中,但这样会导致sql注入问题。

如果我把username的值写为"admin' --",后面的密码就会被–符号注释掉,我直接绕过密码进行登录,这就是sql注入现象。

  •   String sql = "SELECT * FROM t_user WHERE username = '" + username + "' AND password = '" + password + "'";
    

7.2 如何避免sql注入

使用?做占位符,这样用户提交的username和password即使包含–注释符号也会被数据库驱动解析为字符串的形式,不会直接插入到sql语句中,因此就避免了sql注入。

String sql = "SELECT * FROM t_user WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();

7.3 mybatis的两种占位符

经过上面两点的介绍,下面引入mybatis的两种参数符号#{}和${}

1.#{}:相当于占位符?,然后自动解析后,带有单引号,测试中调用接口的方法。

2.${}:相当于字符串拼接方法,不包含单引号,所以如果是字符型字段,需要你手动加上单引号。

8 Mybatis环境搭建(实验一)

记录mybatis_demo01实验记录

1 工程名和包名

1.1 工程名和包名的命名规范

(1)工程名:

  • 一般是表示整个项目,工程名和包名中的项目名字没有强制关联,它们可以完全不同。
  • 有两种命名方式,大驼峰(每个单词首字母大写)和全小写方式,根据自己喜好。

(2)包名:

  1. 单模块工程
  • 单模块工程一般是com.公司名.项目名.功能层(此时省略了模块名)
  • cn.edu.huuc.项目名.功能层或者cn.edu.huuc.功能层,两种方式都可以。
  1. 多模块工程(每一个模块是一个独立的工程)

    • 一般是com.公司名.项目名.模块名.功能层

    •   #### 示例 1:工程名和包名项目名字不同
        
        + **工程名**:`OnlineStorePlatform`
        + **包名**:`com.example.store.user`(项目名是 `store`)
        
        #### 示例 2:工程名和包名项目名字相同
        
        + **工程名**:`ecommerce`
        + **包名**:`com.example.ecommerce.core`
      

1.2 常用的域名前缀


先总结两个常用的域名开头,其他后面用到再记录。

1.comcommercial 的缩写,通常用于表示商业机构公司开发的软件项目

命名格式:com.公司域名.项目名.模块名

2.cn` 是 China 的国家代码顶级域名(ccTLD),通常用于表示中国的机构或组织开发的软件项目

命名格式:cn.机构域名.项目名.模块名

2 maven仓库

2.1 maven的三种仓库

导入坐标后,如果自己电脑的本地仓库没有从maven的中央仓库下载。第三方仓库先了解。

image-20250220194802395

3 setting.xml里面镜像问题总结

  1. 一种方式:改setting.xml
经过测试发现,当设置的setting.xml镜像的mirrof匹配的是特定的具体仓库时候,不论你用的哪个盘的setting.xml文件,默认优先使用mirrof匹配的特定的仓库的那个setting文件。
如果两个setting文件里面的镜像匹配的都是通用仓库,即mirrof为*,此时优先使用用户配置的setting文件。
  1. 另一种方式:在pom里面加坐标。
  • 但是优先级还是用户配置的setting最高,然后才加载这个pom,最后加载中心仓库。
  • 注意一点,pom里面这个原来没有生效,是阿里云的地址写错了https://maven.aliyun.com/nexus/content/groups/public,http要加s,他这可能是旧版的地址,是http没加s无法使用,改后就可以了。

image-20250305194842254

4 其他

  1. jdk 8、11、17长期稳定

  2. power save mode(省电模式开启)导致无法测试,需要关闭才可以。

  3. 补充下maven环境配置:初次配置的时候maven的settings.xml文件在默认路径C:\Users\lenovo.m2\settings.xml没有找到,但是我依然可以下载jar包到仓库中。搜查后,可能是使用了idea安装目录下的全局配置settings.xml.(隐藏了也找不到)。

  4. 编写代码时,怎么设置自动导包?

(1) File—>settings—>Editor-->General-->Auto import 勾选对应选项 --对当前项目生效;

(2) File-->New Projects Setup-->Settings for New Projects—Other Settings--> Auto import 勾选对应选项 ---对以后创建的项目生效。

  1. setting中配置了阿里云的镜像后,还是中央仓库的路径。(已解决,mirrof优先级问题)

    中央仓库路径:https://repo.maven.apache.org/maven2/
    
  2. 映射路径有两种情况:

    1.对应映射路径要和接口或类的全路径一样。

映射文件下的标签:
<mapper namespace="cn.edu.huuc.chapter02_03.mappers.StudentMapper">

核心配置文件下的标签:
<mappers>
           <mapper resource="cn/edu/huuc/chapter02_03/mappers/StudentMapper.xml"/>
<!--        <package name="cn.edu.huuc.chapter02_03.mappers"/>-->
    </mappers>
    
    <typeAliases>
        <package name="cn.edu.huuc.chapter02_03.pojo"  />
    </typeAliases>

2.xml映射文件的目录不一定和接口全路径一样,但是要注意:

  • 必须在mybatis-config.xml指定映射文件的自定义路径。
  • 必须在映射文件的namespace中必须指定接口的全路径。

9 mybatis的crud(实验二)

记录mybatis_demo02实验记录

上面3 相关问题 中记录

3.1 idea中模块问题

idea中创建项目分为两种情况:

  1. 直接创建一个项目,该项目默认有一个子模块,子模块名字默认与项目同名。这时候该项目自带一个模块。适合单体项目开发。
    • 如果想要加模块右键点击项目名->new moudle根据parent选择新建的模块与默认模块是否同级。一般多模块用第二种方式创建,第一种我认为结构不清晰。
  2. 创建一个空项目,然后在这个空项目中添加多个子模块的形式。适合多模块开发。不过建的是一个空项目,需要单独配置maven。

10 动态sql及接口方法参数及返回类型(实验三)

记录mybatis_demo03实验记录

记录在1 动态sql中,上面。

<typeAliases>
    <typeAlias type="com.yzh.mybatis_demo03.pojo.User" alias="User"/>
    <package name="com.yzh.mybatis_demo03.pojo"/>
</typeAliases>

2.https://mvnrepository.com/这个网站作用
(1)是搜索jar包的pom文件用的
(2)也可以在这个网站上单独下载搜索的jar包,点击jar文件就行,pom文件是这个jar包的声明信息。

ctrl+shift+v和.var的效果一样:自动生成代码声明
ctrl+alt+空格是自动提示代码补全(你自己选择要不要用不会自己生成类型)或者自动生成代码变量名,tab是直接代码补全,无提示。
原来一直认为代码补全就是.var,他们是不一样的。

搭建mybatis工程时,设置常用xml模板方法
file->setting->Editor->File and Code Templates,添加后enable勾上重启即可生效。

/创建测试类步骤:
* 1.一个测试类对应一个测试方法
* 2.用工厂构建类的build方法造一个工厂
* 3.调用sqlSessionFactory的接口方法openSession()生成sqlsession对象
* 4.用sqlsession接口的方法查询或者用面向接口变成查询也可以
/
/*注意项:
* 1.Resources的包是import org.apache.ibatis.io.Resources;这个,别导错
* 2.注意SqulSessionFactoryBuilder是类,需要new
* 3.sqlsession和sqlSessionFactory是接口类型对象
* */

/如果一直抛出异常不处理,文件存在没事,如果文件不存在,将会报错。
所以还是要捕获异常,即使文件不存在他也不会报错,保护程序不被崩溃
/

  //工具类中抛出异常,测试类调用此方法还需要抛出或者捕获异常

// public static SqlSession getSqlSession() throws IOException {
// InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
// SqlSession sqlSession = sqlSessionFactory.openSession();
// return sqlSession;
// }
//工具类中捕获异常,测试类调用此方法不需要任何处理
public static SqlSession getSqlSession() {
InputStream is = null;
try {
is = Resources.getResourceAsStream("mybatis-config.xml");
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}

6.

  <select id="findAllUser" resultType="User">
      select * from users;
  </select>
<!--注意:mybatis-config.xml里面的mapper有两种常用写法(还有两种不常用的不记录)
         1.<mapper resource="mapper/UserMapper.xml"/>
         2.<package name="com.yzh.mybatis_demo03.mapper"/>
         这种写法千万注意:此时的映射文件路径要和对应的接口的包名全类名一致,否则报错-->
 <!--<resultMap id="StudentResultMap" type="Student">
     <id property="id" column="sid"/>
     <result property="name" column="sname"/>
     <result property="age" column="sage"/>
 </resultMap>-->

把id类型改为Integer类型就可以设为null,
// Integer定义的变量是一个对象,对象可以为空,基本数据类型不可以
Customer customer = new Customer(2, "jack", "worker", "null");
10.
没使用mybatis框架前的字符串拼接形式:
String sql = "SELECT * FROM t_user WHERE username = '" + username + "'"

/* 这个更新操作注意,
1.第一次我直接这样写日志显示数据更新了,但是数据库没变化,
后来最后提交了事务进行查看,还是不行,最后发现提交事务的sqlsession是新建的的,
提交的压根不是第一个sqlsession绘画的事务,所以无法更新。
2.打印台
2025-03-12 21:50:23,623 44 [ main] DEBUG source.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
2025-03-12 21:50:23,624 45 [ main] DEBUG source.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
2025-03-12 21:50:23,624 45 [ main] DEBUG source.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
2025-03-12 21:50:23,624 45 [ main] DEBUG source.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
这四条消息时框架初始化关闭之前所有的连接
2025-03-12 21:50:23,690 111 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Opening JDBC Connection
2025-03-12 21:50:23,795 216 [ main] DEBUG source.pooled.PooledDataSource - Created connection 1337335626.
2025-03-12 21:50:23,795 216 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.my
这三条是新获得的连接,第三条设置自动提交事务是关闭的,所以需要手动提交事务*/

// public void testUpdateCustomerBySet() {
// CustomerMapper customerMapper = SqlSessionUtils.getSqlSession().getMapper(CustomerMapper.class);
// int i = customerMapper.updateCustomerBySet(new Customer(1, "joys", "java架构师", "null"));
// if (i > 0) {
// System.out.println("修改成功");
// } else {
// System.out.println("修改失败");
// }
// SqlSessionUtils.getSqlSession().commit();

    SqlSession sqlSession = SqlSessionUtils.getSqlSession();

    CustomerMapper customerMapper = sqlSession.getMapper(CustomerMapper.class);
    int i = customerMapper.updateCustomerBySet(new Customer(3, "汤姆", "java架构师", null));
    if (i > 0) {
        System.out.println("修改成功");
    } else {
        System.out.println("修改失败");
    }
    sqlSession.commit();
    sqlSession.close();
}
也不会成影响,
    3.sql语句的单行注释--和多行注释/*...*/只要里面带#都会被mybatis解析。
    证明,mybatis会对#{}带有#号的进行解析,即使处于注释中->

14.

posted @ 2025-04-28 21:05  JSESSIONID  阅读(12)  评论(0)    收藏  举报