一、了解MyBatis 1.mybatis历史(百度百科)
MyBatis 本是apache的一个开源项目【iBatis】, 2010年这个项目由apache software foundation(Apache软件基金会) 迁移到了google code(谷歌的代码托管平台),并且改名为MyBatis ,2013年11月迁移到Github。
2、作用 (百度百科)
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
3、说说持久化 持久化是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存)。
程序产生的数据首先都是在内存。
内存是不可靠的,他丫的一断电数据就没了。
那可靠的存储地方是哪里?硬盘、U盘、光盘等。
我们的程序在运行时说的持久化通常就是指将内存的数据存在硬盘。
4、说说持久层 其实分层的概念已经谈到过:
业务是需要操作数据的
数据是在磁盘上的
具体业务调用具体的数据库操作,耦合度太高,复用性太差
将操作数据库的代码统一抽离出来,自然就形成了介于业务层和数据库中间的独立的层
5、聊聊ORM ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。
jpa (Java Persistence API)是java持久化规范,是orm框架的标准,主流orm框架都实现了这个标准。
hibernate :全自动的框架,强大、复杂、笨重、学习成本较高,不够灵活,实现了jpa规范。Java Persistence API(Java 持久层 API)
MyBatis :半自动的框架(懂数据库的人 才能操作) 必须要自己写sql,不是依照的jpa规范实现的。
很多人青睐 MyBatis ,原因是其提供了便利的 SQL 操作,自由度高,封装性好…… JPA对复杂 SQL 的支持不好,没有实体关联的两个表要做 join ,的确要花不少功夫。
6、MyBatis的优点和缺点
sql语句与代码分离,存放于xml配置文件中:
优点 :便于维护管理,不用在java代码中找这些语句;
缺点 : JDBC方式可以用打断点的方式调试,但是MyBatis调试比较复杂,一般要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。
用逻辑标签控制动态SQL的拼接:
优点 :用标签代替编写逻辑代码;
缺点 :拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。不要使用变通的手段来应对这种复杂的语句。
查询的结果集与java对象自动映射:
优点 :保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。
缺点 :对开发人员所写的SQL依赖很强。
编写原生SQL:
优点 :接近JDBC,比较灵活。
缺点 :对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如MySQL数据库编程Oracle数据库,部分的SQL语句需要调整。
最重要的一点,使用的人多!公司需要!
二、搭建个环境 1、建立数据库 1 2 3 4 5 6 7 8 9 10 11 CREATE DATABASE `ssm`;USE `ssm`; DROP TABLE IF EXISTS `user `;CREATE TABLE `user ` (`id` int (20 ) NOT NULL , `username` varchar (30 ) DEFAULT NULL , `password` varchar (30 ) DEFAULT NULL , PRIMARY KEY (`id`)) ENGINE= InnoDB DEFAULT CHARSET= utf8; insert into `user `(`id`,`username`,`password`) values (1 ,'itnanls' ,'123456' ),(2 ,'itlils' ,'abcdef' ),(3 ,'ydlclass' ,'987654' );
2、构建一个工程
2.1 修改配置文件pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > org.example</groupId > <artifactId > mybatis_text</artifactId > <version > 1.0-SNAPSHOT</version > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <maven.compiler.encoding > UTF-8</maven.compiler.encoding > <java.version > 11</java.version > <maven.compiler.source > 11</maven.compiler.source > <maven.compiler.target > 11</maven.compiler.target > </properties > <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.11</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.6</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.30</version > <scope > runtime</scope > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.24</version > <scope > provided</scope > </dependency > <dependency > <groupId > ch.qos.logback</groupId > <artifactId > logback-classic</artifactId > <version > 1.4.5</version > </dependency > </dependencies > <dependencyManagement > <dependencies > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13</version > <scope > test</scope > </dependency > </dependencies > </dependencyManagement > </project >
2.2 配置mybatis-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql:///ssm?useSSL=false" /> <property name ="username" value ="root" /> <property name ="password" value ="123456" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="UserMapper.xml" /> </mappers > </configuration >
需要修改数据库连接信息
1 2 3 4 <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql:///ssm?useSSL=false" /> <property name ="username" value ="root" /> <property name ="password" value ="123456" />
2.3 配置UserMapper.xml 1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="text" > <select id ="selectAll" resultType ="com.cwwwxl.pojo.User" > select * from user; </select > </mapper >
2.4 配置 log4j.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?xml version="1.0" encoding="UTF-8" ?> <configuration > <property name ="pattern" value ="%d{yyyy-MM-dd HH:mm:ss} %c [%thread] %-5level %msg%n" /> <property name ="log_dir" value ="d:/logs" /> <appender name ="console" class ="ch.qos.logback.core.ConsoleAppender" > <target > System.out</target > <encoder class ="ch.qos.logback.classic.encoder.PatternLayoutEncoder" > <pattern > ${pattern}</pattern > </encoder > </appender > <appender name ="file" class ="ch.qos.logback.core.FileAppender" > <encoder class ="ch.qos.logback.classic.encoder.PatternLayoutEncoder" > <pattern > ${pattern}</pattern > </encoder > <file > ${log_dir}/sql.log</file > </appender > <root level ="ALL" > <appender-ref ref ="console" /> </root > <logger name ="mybatis.sql" level ="debug" additivity ="false" > <appender-ref ref ="console" /> <appender-ref ref ="file" /> </logger > </configuration >
2.5 新建User类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.cwwwxl.pojo;public class User { private String id ; private String username; private String password; @Override public String toString () { return "User{" + "id='" + id + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + '}' ; } public String getId () { return id; } public void setId (String id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getPassword () { return password; } public void setPassword (String password) { this .password = password; } }
2.6 新建MyBatisDome 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.cwwwxl.pojo; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MyBatisDome { public static void main(String[] args) { //加载配置文件 String resource = "mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); List<Object> objects = sqlSession.selectList("text.selectAll"); //加载sql文件 System.out.println(objects); //打印日志 sqlSession.close();//释放资源 } }
出现以下信息查询成功。
3.DTD DTD(Document Type Definition)即文档类型定义,是一种XML约束模式语言,是XML文件的验证机制
如下所示是公共DTD示例。
1 2 3 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >
关于DTD的声明解释如下:
1、DTD声明始终以!DOCTYPE开头,空一格后跟着文档根元素的名称。
2、根元素名:configuration。所以每一个标签库定义文件都是以taglib为根元素的,否则就不会验证通过。
3、PUBLIC “-//mybatis.org//DTDopen in new window Config 3.0//EN,这是一个公共DTD的名称(私有的使用SYSTEM表示)。这个东西命名是有些讲究的。首先它是以”-“开头的,表示这个DTD不是一个标准组织制定的。(如果是ISO标准化组织批准的,以“ISO”开头)。接着就是双斜杠“//”,跟着的是DTD所有者的名字,很明显这个DTD是MyBatis公司定的。接着又是双斜杠“//”,然后跟着的是DTD描述的文档类型,可以看出这份DTD描述的是DTD Config 3.0的格式。再跟着的就是“//”和ISO 639语言标识符。
4、绿色的字”http://mybatis.org/dtd/mybatis-3-config.dtdopen in new window “,表示这个DTD的位置。
疑问:是不是xml分析器都会到java.sun.com上去找这个dtd呢?答案是否定的,xml分析器首先会以某种机制查找公共DTD的名称,查到了,则以此为标准,如果查不到,再到DTD位置上去找。
(2)XSD 文档结构描述XML Schema Definition 缩写,这种文件同样可以用来定义我们xml文件的结构!
我们看看pom文件的xml头部:
1 2 3 4 <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd " >
1、第一行的xmlns代表了一个xml文件中的一个命名空间,通常是一个唯一的字符串,一般使用一个url,因为不会重复嘛。
它的语法如下:
1 xmlns:namespace-prefix="namespaceURI"
后边什么也不加,代表默认命名空间,我们在书写标签的时候不需要加任何前缀。
如果我将其改为:
1 xmlns:c="http://maven.apache.org/POM/4.0.0"
image-20211104144031737
2、xmlns:xsi 定义了一个命名空间前缀 xsi 对应的唯一字符串 http://www.w3.org/2001/XMLSchema-instance。但这个open in new window xmlns:xsi 在不同的 xml 文档中似乎都会出现。 这是因为, xsi 已经成为了一个业界默认的用于 XSD((XML Schema Definition) 文件的命名空间。 而 XSD 文件(也常常称为 Schema 文件)是用来定义 xml 文档结构的。剩余两行的目的在于为我们的命名空间指定对应的xsd文件。
事实上我们这么写也是可以的:
image-20211104144300243
上面这行的语法其实是, xsi:schemaLocation = “ns1url xsd1 ns2url xsd2”
XML Schema相对于DTD的优点在于:
XML Schema基于XML,没有专门的语法。
XML Schema可以像其他XML文件一样解析和处理。
XML Schema比DTD提供了更丰富的数据类型。
XML Schema提供可扩充的数据模型。
XML Schema支持综合命名空间。
XML Schema支持属性组。
4、编写实体类
lombok
平时的工作中写setter和getter以及toString方法是不是已经烦了,每次添加一个字段都要重新添加这些方法。
今天我们学习一个神器,从此再也不用写这些重复的代码了,它们在编译的时候动态的帮我们生成这些代码。
javac对源代码进行分析,生成了一棵抽象语法树(AST)
运行过程中调用实现了“JSR 269 API”的Lombok程序
此时Lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
javac使用修改后的抽象语法树(AST)生成字节码文件,即给class增加新的节点(代码块)
1,首先,我们必须安装一个插件,否则编译的时候会报错,你没有写setter方法,又去调用它当然不能编译:
image-20211020113926489
2、引入依赖,lombok在编译的时候,会根据我们的注解动态生成我们需要的构造方法,setter和getter等,运行的时候就没用了。所以scope选择provided。
1 2 3 4 5 6 7 <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.16</version > <scope > provided</scope > </dependency >
从今往后,只需要在对应的类上加上这几个注解,就能完成对应的编译工作
@AllArgsConstructor:生成全参构造器。
@NoArgsConstructor:生成无参构造器。
@Getter/@Setter: 作用类上,生成所有成员变量的getter/setter方法;作用于成员变量上,生成该成员变量的getter/setter方法。可以设定访问权限及是否懒加载等。
@Data:作用于类上,是以下注解的集合:@ToString @EqualsAndHashCode @Getter @Setter @RequiredArgsConstructor
@Log:作用于类上,生成日志变量。针对不同的日志实现产品,有不同的注解。
注解还有很多,自行学习。
1 2 3 4 5 6 7 8 9 10 11 @Data @AllArgsConstructor @NoArgsConstructor public class User implements Serializable { private static final Long serialVersionUID = 1L ; private int id; private String username; private String password; }
此时我们的User是不是变得很简洁呢?
我们随便写一个main方法,然后编译一下:
编译后的结果是这个样子的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 public class User implements Serializable { private static final Long serialVersionUID = 1L ; private int id; private String username; private String password; public static void main (String[] args) { } public int getId () { return this .id; } public String getUsername () { return this .username; } public String getPassword () { return this .password; } public void setId (int id) { this .id = id; } public void setUsername (String username) { this .username = username; } public void setPassword (String password) { this .password = password; } public boolean equals (Object o) { if (o == this ) { return true ; } else if (!(o instanceof User)) { return false ; } else { User other = (User)o; if (!other.canEqual(this )) { return false ; } else if (this .getId() != other.getId()) { return false ; } else { Object this$username = this .getUsername(); Object other$username = other.getUsername(); if (this $username == null ) { if (other$username != null ) { return false ; } } else if (!this $username.equals(other$username)) { return false ; } Object this$password = this .getPassword(); Object other$password = other.getPassword(); if (this $password == null ) { if (other$password != null ) { return false ; } } else if (!this $password.equals(other$password)) { return false ; } return true ; } } } protected boolean canEqual (Object other) { return other instanceof User; } public int hashCode () { int PRIME = true ; int result = 1 ; int result = result * 59 + this .getId(); Object $username = this .getUsername(); result = result * 59 + ($username == null ? 43 : $username.hashCode()); Object $password = this .getPassword(); result = result * 59 + ($password == null ? 43 : $password.hashCode()); return result; } public String toString () { int var10000 = this .getId(); return "User(id=" + var10000 + ", username=" + this .getUsername() + ", password=" + this .getPassword() + ")" ; } public User (int id, String username, String password) { this .id = id; this .username = username; this .password = password; } public User () { } }
我们发现,编译后注解没了,其他的都有了,自然运行时就能调用了呀!
第一个测试程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.cwwwxl.pojo.entity;import lombok.extern.slf4j.Slf4j;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.InputStream;import java.util.List;@Slf4j public class MyBatisDome { public static void main (String[] args) { String resource = "mybatis-config.xml" ; InputStream inputStream = null ; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { List<Object> list = session.selectList("text.selectAll" ); for (Object user :list) { System.out.println(user); } session.close(); } } }
5.增删改查 通过使用mybatis对数据的增删改查操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 package com.cwwwxl.pojo.entity;import lombok.extern.slf4j.Slf4j;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.InputStream;import java.util.List;@Slf4j public class MyBatisDome { public static void main (String[] args) throws IOException { MyBatisDome myBatisDome = new MyBatisDome (); myBatisDome.deleteUser(); } public void ByID () throws IOException { String resource = "mybatis-config.xml" ; InputStream inputStream = null ; inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory session = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = session.openSession(); Object o = sqlSession.selectOne("text.ByID" , 3 ); System.out.println(o); sqlSession.close(); } public void inserUser () throws IOException { String resource="mybatis-config.xml" ; InputStream inputStream = null ; inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory build = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = build.openSession(); User User=new User (); User.setId("4" ); User.setUsername("wangxinglong" ); User.setPassword("1233789" ); int wangxinglong = sqlSession.insert("text.inserUser" ,User); sqlSession.commit(); System.out.println(wangxinglong); sqlSession.close(); } public void updateUser () throws IOException { String resource="mybatis-config.xml" ; InputStream inputStream = null ; inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory build = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = build.openSession(); User User=new User (); User.setId("4" ); User.setUsername("admin" ); User.setPassword("admin" ); int update = sqlSession.update("text.updateUser" , User); sqlSession.commit(); System.out.println(update); sqlSession.close(); } public void deleteUser () throws IOException { String resource="mybatis-config.xml" ; InputStream inputStream = null ; inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory build = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = build.openSession(); int delete = sqlSession.delete("text.deleteUser" , 3 ); System.out.println(delete); sqlSession.commit(); sqlSession.close(); } }
UserMaper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="text" > <select id ="selectAll" resultType ="com.cwwwxl.pojo.entity.User" > select * from user; </select > <select id ="ByID" resultType ="com.cwwwxl.pojo.entity.User" > select * from user where id=#{id} </select > <insert id ="inserUser" parameterType ="com.cwwwxl.pojo.entity.User" > insert into user(id,username,password) values (#{id},#{username},#{password}) </insert > <update id ="updateUser" parameterType ="com.cwwwxl.pojo.entity.User" > update user set username=#{username},password=#{password} where id=#{id} </update > <delete id ="deleteUser" > delete from user where id=#{id} </delete > </mapper >