一、三层架构

1.什么是三层架构
在项目开发中,遵循的一种形式模式.分为三层.
1)界面层:用来接收客 户端的输入,调用业务逻辑层进行功能处理,返回结果给客户端.过去的servlet就是界面层的功能.
2)业务逻辑层:用来进行整个项目的业务逻辑处理,向上为界面层提供处理结果,向下问数据访问层要数据.
3)数据访问层:专门用来进行数据库的增删改查操作,向上为业务逻辑层提供数据.

各层之间的调用顺序是固定的,不允许跨层访问.
界面层<———->业务逻辑层<———>数据访问层

2.生活中的三层架构
image.png

二、搭建MyBatis环境

1.创建MySql数据库

  1. use ssm;
  2. CREATE TABLE `student` (
  3. `id` int(11) AUTO_INCREMENT primary key ,
  4. `name` varchar(255) DEFAULT NULL,
  5. `email` varchar(255) DEFAULT NULL,
  6. `age` int(11) DEFAULT NULL
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  8. insert into student(name,email,age) values('张三','zhangsan@126.com',22);
  9. insert into student(name,email,age) values('李四','lisi@126.com',21);
  10. insert into student(name,email,age) values('王五','wangwu@163.com',22);
  11. insert into student(name,email,age) values('赵六','zhaoliun@qq.com',24);
  12. select * from student;

2.创建工程

1.创建一个空 Project

image.png

2.创建一个quickstart meaven 的Modules

image.png

3.修改目录

image.png

4.修改pom.xml

1)添加依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>junit</groupId>
  4. <artifactId>junit</artifactId>
  5. <version>4.11</version>
  6. <scope>test</scope>
  7. </dependency>
  8. <!--添加MyBatis框架的依赖-->
  9. <dependency>
  10. <groupId>org.mybatis</groupId>
  11. <artifactId>mybatis</artifactId>
  12. <version>3.5.6</version>
  13. </dependency>
  14. <!--添加mysql依赖-->
  15. <dependency>
  16. <groupId>mysql</groupId>
  17. <artifactId>mysql-connector-java</artifactId>
  18. <version>8.0.17</version>
  19. </dependency>
  20. </dependencies>

2)添加资源文件指定

  1. <!--添加资源文件的指定-->
  2. <build>
  3. <resources>
  4. <resource>
  5. <directory>src/main/java</directory>
  6. <includes>
  7. <include>**/*.xml</include>
  8. <include>**/*.properties</include>
  9. </includes>
  10. </resource>
  11. <resource>
  12. <directory>src/main/resources</directory>
  13. <includes>
  14. <include>**/*.xml</include>
  15. <include>**/*.properties</include>
  16. </includes>
  17. </resource>
  18. </resources>
  19. </build>

3.在idea中添加数据库的可视化

image.png

4.添加jdbc.properties属性文件(数据库的配置)

image.png

  1. jdbc.driver=com.mysql.cj.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
  3. jdbc.username=root
  4. jdbc.password=123456

5.添加SqlMapConfig.xml文件,MyBatis的核心配置文件

image.png

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4. <configuration>
  5. <!--读取属性文件(jdbc.properties)
  6. 属性:
  7. resources:从resources目录下找指定名称的文件加载
  8. url:使用绝对路径加载属性文件
  9. D:\course\16.MyBatis\04_project\mybatisall\mybatis_001_student\src\main\resources\jdbc.properties
  10. -->
  11. <properties resource="jdbc.properties"></properties>
  12. <!--配置数据库的环境变量(数据库连接配置)
  13. default:使用下面的environment标签的id属性进行指定配置
  14. -->
  15. <environments default="development">
  16. <!--开发时在公司使用的数据库配置
  17. id:就是提供给environments的default属性使用
  18. -->
  19. <environment id="development">
  20. <!--配置事务管理器
  21. type:指定事务管理的方式
  22. JDBC:事务的控制交给程序员处理
  23. MANAGED:由容器(Spring)来管理事务
  24. -->
  25. <transactionManager type="JDBC"></transactionManager>
  26. <!--配置数据源
  27. type:指定不同的配置方式
  28. JNDI:java命名目录接口,在服务器端进行数据库连接池的管理
  29. POOLED:使用数据库连接池
  30. UNPOLLED:不使用数据库连接池
  31. -->
  32. <dataSource type="POOLED">
  33. <!--配置数据库连接的基本参数
  34. private String driver;
  35. private String url;
  36. private String username;
  37. private String password;
  38. -->
  39. <property name="driver" value="${jdbc.driver}"></property>
  40. <property name="url" value="${jdbc.url}"></property>
  41. <property name="username" value="${jdbc.username}"></property>
  42. <property name="password" value="${jdbc.password}"></property>
  43. </dataSource>
  44. </environment>
  45. <!--&lt;!&ndash;在家的数据库配置&ndash;&gt;-->
  46. <!--<environment id="home">-->
  47. <!--<transactionManager type=""></transactionManager>-->
  48. <!--<dataSource type=""></dataSource>-->
  49. <!--</environment>-->
  50. <!--&lt;!&ndash;上线后的数据库配置&ndash;&gt;-->
  51. <!--<environment id="online">-->
  52. <!--<transactionManager type=""></transactionManager>-->
  53. <!--<dataSource type=""></dataSource>-->
  54. <!--</environment>-->
  55. </environments>
  56. <!--注册mapper.xml文件
  57. resource:从resources目录下找指定名称的文件注册
  58. url:使用绝对路径注册
  59. class:动态代理方式下的注册
  60. -->
  61. <mappers>
  62. <mapper resource=""></mapper>
  63. </mappers>
  64. </configuration>

添加:数据库连接池的基本概念
image.png

6.创建实体类Student,用来封装数据

image.png

  1. public class Student {
  2. private Integer id;
  3. private String name;
  4. private String email;
  5. private Integer age;
  6. //无参构造方法
  7. //有参构造
  8. //除了主键的有参构造
  9. //set()和get()
  10. //toString()
  11. }

7.添加完成学生表的增删改查的功能的StudentMapper.xml文件

image.png
注意:该文件位置可放在任意位置

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <!--
  5. mapper:是整个文件的大标签,用来开始和结束xml文件
  6. 属性:
  7. namespace:指定命名空间(相当于包名),用来区分不同mapper.xml文件中相同的id属性
  8. -->
  9. <mapper namespace="csy">
  10. <!--
  11. 完成查询全部学生的功能
  12. List<Student> getALL();
  13. resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型
  14. parameterType:如果有参数,则通过它来指定参数的类型
  15. -->
  16. <select id="getAll" resultType="com.bjpowernode.pojo.Student" >
  17. select id,name,email,age
  18. from student
  19. </select>
  20. </mapper>

在SqlMapConfig.xml中注册mapper.xml文件

  1. <!--注册mapper.xml文件
  2. resource:从resources目录下找指定名称的文件注册
  3. url:使用绝对路径注册
  4. class:动态代理方式下的注册
  5. -->
  6. <mappers>
  7. <mapper resource="StudentMapper.xml"></mapper>
  8. </mappers>

8.创建测试类,进行功能测试

  1. public class MyTest {
  2. @Test
  3. public void testA() throws IOException {
  4. //使用文件流读取核心配置文件SqlMapConfig.xml
  5. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  6. //创建SqlSessionFactory工厂
  7. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  8. //取出sqlSession的对象
  9. SqlSession sqlSession = factory.openSession();
  10. //完成查询操作
  11. List<Student> list =sqlSession.selectList("csy.getALl");
  12. list.forEach(student -> System.out.println(student));
  13. //关闭sqlSession
  14. sqlSession.close();
  15. }
  16. }

9.完成增删改查

按主键查询学生

  1. <!--
  2. 按主键id查询学生信息
  3. Student getById(Integer id);
  4. -->
  5. <select id="getById" parameterType="int" resultType="com.bjpowernode.pojo.Student">
  6. select id,name,email,age
  7. from student
  8. where id=#{id}
  9. </select>
  1. @Test
  2. public void testGetById() throws IOException {
  3. //读取核心配置文件
  4. InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");
  5. //创建SqlSessionFactory对象
  6. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  7. //取出SqlSession
  8. SqlSession sqlSession = factory.openSession();
  9. //按主键查学生
  10. Student stu =sqlSession.selectOne("csy.getById",1);
  11. System.out.println(stu);
  12. //关闭SqlSession'
  13. sqlSession.close();
  14. }

完成模糊查询

  1. <!--
  2. 按学生模糊查询
  3. List<Student> getByName();
  4. -->
  5. <select id="getByName" parameterType="string" resultType="com.bjpowernode.pojo.Student">
  6. select id,name,email,age
  7. from student
  8. where name like '%${name}%'
  9. </select>
  1. @Test
  2. public void testGetByName() throws IOException {
  3. //读取核心配置文件
  4. InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");
  5. //创建SqlSessionFactory对象
  6. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  7. //取出SqlSession
  8. SqlSession sqlSession = factory.openSession();
  9. //按主键查学生
  10. List<Student> list =sqlSession.selectList("csy.getByName","张");
  11. list.forEach(student -> System.out.println(student));
  12. //关闭SqlSession'
  13. sqlSession.close();
  14. }

增加学生

  1. <!--
  2. 增加学生
  3. int insert(Student stu)
  4. 实体类:
  5. private Integer id;
  6. private String name;
  7. private String email;
  8. private Integer age;
  9. -->
  10. <insert id="insert" parameterType="com.bjpowernode.pojo.Student">
  11. insert into student(name,email,age) values(#{name},#{email},#{age})
  12. </insert>
  1. @Test
  2. public void testInsert() throws IOException {
  3. //1.读取核心配置文件
  4. InputStream in =Resources.getResourceAsStream("SqlMapConfig.xml");
  5. //2.创建SqlSessionFactory对象
  6. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  7. //3.取出SqlSession
  8. SqlSession sqlSession = factory.openSession();
  9. //4.调用方法 //通过pojo实体类无主键有参构造方法传进去
  10. int num=sqlSession.insert("csy.insert",new Student("haha","haha126@qq.com",23));
  11. //切记切记:在所有的增删改查后必须手动提交事务
  12. sqlSession.commit();
  13. sqlSession.close();
  14. }

删除学生

  1. <!--
  2. 按主键删除学生
  3. int delete (Integet id);
  4. -->
  5. <delete id="delete" parameterType="int">
  6. delete from student where id=#{id}
  7. </delete>
  1. @Test
  2. public void testDelete() throws IOException {
  3. //1.读取核心配置文件
  4. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  5. //2.创建SqlSessionFactory对象
  6. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  7. //3.取出SqlSession
  8. SqlSession sqlSession = factory.openSession();
  9. //4.调用方法
  10. int num = sqlSession.delete("csy.delete", 1);
  11. System.out.println(num);
  12. //切记切记:在所有的增删改查后必须手动提交事务
  13. sqlSession.commit();
  14. sqlSession.close();
  15. }

更新学生

  1. <!--
  2. 更新学生
  3. int update(Student stu)
  4. -->
  5. <update id="update" parameterType="com.bjpowernode.pojo.Student">
  6. update student set name=#{name},email=#{email},age=#{age}
  7. where id=#{id}
  8. </update>
  1. @Test
  2. public void testUpdate() throws IOException {
  3. //1.读取核心配置文件
  4. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  5. //2.创建SqlSessionFactory对象
  6. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  7. //3.取出SqlSession
  8. SqlSession sqlSession = factory.openSession();
  9. //4.调用方法
  10. int num=sqlSession.update("csy.update",new Student(3,"hehe","hehe@126.com",30));
  11. System.out.println(num);
  12. sqlSession.commit();
  13. sqlSession.close();
  14. }

10. SqlMapConfig.xml文件的优化

优化测试类

  1. public class MyTest {
  2. SqlSession sqlSession;
  3. @Before //在所有的@Test方法执行前先执行的代码
  4. public void openSqlSession() throws IOException {
  5. //1.读取核心配置文件
  6. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  7. //2.创建SqlSessionFactory对象
  8. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  9. //3.取出SqlSession
  10. sqlSession = factory.openSession();
  11. }
  12. @After
  13. public void closeSqlSession(){
  14. //关闭sqlSession
  15. sqlSession.close();
  16. }
  17. @Test
  18. public void testInsert() throws IOException {
  19. int num = sqlSession.insert("csy.insert", new Student("haha", "haha126@qq.com", 23));
  20. //切记切记:在所有的增删改查后必须手动提交事务
  21. sqlSession.commit();
  22. }
  23. }

实体类别名注册

单个实体类注册

  1. <properties resource="jdbc.properties"></properties>
  2. <!--设置日志输出底层执行代码-->
  3. <!--注册实体类的别名-->
  4. <typeAliases>
  5. <!--单个实体类别名注册-->
  6. <typeAlias type="com.bjpowernode.pojo.Student" alias="student"></typeAlias>
  7. </typeAliases>
  8. <environments default="development">
  9. ....
  10. </environment>
  1. <update id="update" parameterType="student">
  2. update student set name=#{name},email=#{email},age=#{age}
  3. where id=#{id}
  4. </update>

批量注册别名
如果类名是studentone 则别名为 studentOne

  1. <typeAliases>
  2. <!--批量注册别名
  3. 别名是类名的驼峰命名法(规范)-->
  4. <package name="com.bjpowernode.pojo"></package>
  5. </typeAliases>
  1. <update id="update" parameterType="student">
  2. update student set name=#{name},email=#{email},age=#{age}
  3. where id=#{id}
  4. </update>

设置日志输出

  1. <!--设置日志输出底层执行代码-->
  2. <settings>
  3. <setting name="logImpl" value="STDOUT_LOGGING"/>
  4. </settings>

三、动态代理

1.动态代理存在的意义

在三层架构中,业务逻辑层要通过接口访问数据访问层的功能.动态代理可以实现.

image.png

2.动态代理的七个规范

动态代理的实现规范:
1)UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下.
2)UsersMapper.xml文件与UsersMapper.java的接口的文件名必须一致,后缀不管.
3)UserMapper.xml文件中标签的id值与与UserMapper.java的接口中方法的名称完全一致.
4)UserMapper.xml文件中标签的parameterType属性值与与UserMapper.java的接口中方法的参数类型完全一致.
5)UserMapper.xml文件中标签的resultType值与与UserMapper.java的接口中方法的返回值类型完全一致.
6)UserMapper.xml文件中namespace属性必须是接口的完全限定名称com.bjpowernode.mapper.UsersMapper
7)在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称com.bjpowernode.mapper.UsersMapper.

3.动态代理的实现步骤

1.创建表

  1. use ssm;
  2. -- ----------------------------
  3. -- Table structure for `users`
  4. -- ----------------------------
  5. DROP TABLE IF EXISTS `users`;
  6. CREATE TABLE `users` (
  7. `id` int(11) NOT NULL AUTO_INCREMENT,
  8. `username` varchar(32) COMMENT '用户名称',
  9. `birthday` date DEFAULT NULL COMMENT '生日',
  10. `sex` char(2) DEFAULT NULL COMMENT '性别',
  11. `address` varchar(256) DEFAULT NULL COMMENT '地址',
  12. PRIMARY KEY (`id`)
  13. ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
  14. -- ----------------------------
  15. -- Records of user
  16. -- ----------------------------
  17. INSERT INTO `users` VALUES (1, '王五', '2000-09-10', '2', '安徽');
  18. INSERT INTO `users` VALUES (2, '张三', '2001-07-12', '1', '北京市');
  19. INSERT INTO `users` VALUES (3, '张小明', '1999-02-22', '1', '河南');
  20. INSERT INTO `users` VALUES (4, '陈小亮', '2002-11-19', '1', '辽宁');
  21. INSERT INTO `users` VALUES (5, '张三丰', '2001-03-10', '1', '上海市');
  22. INSERT INTO `users` VALUES (6, '陈小明', '2002-01-19', '1', '重庆市');
  23. INSERT INTO `users` VALUES (7, '王五四', '2001-05-13', '2', '天津市');
  24. select * from users;

2.创建工程

1)创建一个quickstart meaven 的Modules

2)修改目录

image.png

3)修改pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.bjpowerndoe</groupId>
  7. <artifactId>mybatis_02_student</artifactId>
  8. <version>1.0</version>
  9. <properties>
  10. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  11. <maven.compiler.source>17</maven.compiler.source>
  12. <maven.compiler.target>17</maven.compiler.target>
  13. </properties>
  14. <dependencies>
  15. <dependency>
  16. <groupId>junit</groupId>
  17. <artifactId>junit</artifactId>
  18. <version>4.11</version>
  19. <scope>test</scope>
  20. </dependency>
  21. <!--添加MyBatis框架的依赖-->
  22. <dependency>
  23. <groupId>org.mybatis</groupId>
  24. <artifactId>mybatis</artifactId>
  25. <version>3.5.6</version>
  26. </dependency>
  27. <!--添加mysql依赖-->
  28. <dependency>
  29. <groupId>mysql</groupId>
  30. <artifactId>mysql-connector-java</artifactId>
  31. <version>8.0.17</version>
  32. </dependency>
  33. </dependencies>
  34. <!--添加资源文件的指定-->
  35. <build>
  36. <resources>
  37. <resource>
  38. <directory>src/main/java</directory>
  39. <includes>
  40. <include>**/*.xml</include>
  41. <include>**/*.properties</include>
  42. </includes>
  43. </resource>
  44. <resource>
  45. <directory>src/main/resources</directory>
  46. <includes>
  47. <include>**/*.xml</include>
  48. <include>**/*.properties</include>
  49. </includes>
  50. </resource>
  51. </resources>
  52. </build>
  53. </project>

3.完成resources下面的文件

1)添加jdbc.properties属性文件(数据库的配置)

image.png

  1. jdbc.driver=com.mysql.cj.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
  3. jdbc.username=root
  4. jdbc.password=123456

2)添加SqlMapConfig.xml文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4. <configuration>
  5. <properties resource="jdbc.properties"></properties>
  6. <settings>
  7. <setting name="logImpl" value="STDOUT_LOGGING"/>
  8. </settings>
  9. <typeAliases>
  10. <package name="com.bjpowerndoe.pojo"></package>
  11. </typeAliases>
  12. <environments default="development">
  13. <environment id="development">
  14. <transactionManager type="JDBC"></transactionManager>
  15. <dataSource type="POOLED">
  16. <property name="driver" value="${jdbc.driver}"></property>
  17. <property name="url" value="${jdbc.url}"></property>
  18. <property name="username" value="${jdbc.username}"></property>
  19. <property name="password" value="${jdbc.password}"></property>
  20. </dataSource>
  21. </environment>
  22. </environments>
  23. <mappers>
  24. <mapper class=" "></mapper>
  25. </mappers>
  26. </configuration>

4.添加实体类

image.png

  1. public class Users {
  2. private Integer id;
  3. private String userName;
  4. private Date birthday;
  5. private String sex;
  6. private String address;
  7. //无参构造
  8. //有参构造
  9. //有参构造不包括主键
  10. //set()和get()
  11. //toString()
  12. }

5.完成mapper下面的文件

1.新建UsersMapper接口

image.png

  1. public interface UsersMapper {
  2. //查询全部用户信息
  3. List<Users> getAll();
  4. }

2.新建UsersMapper.xml文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.bjpowernode.mapper.UsersMapper">
  5. <!--
  6. //查询全部用户信息
  7. List<Users> getAll();
  8. -->
  9. <select id="getAll" resultType="users">
  10. select id,username,birthday,sex,address
  11. from users;
  12. </select>
  13. </mapper>

6.添加测试类,测试功能

  1. public class MyTest {
  2. SqlSession sqlSession;
  3. @Before
  4. public void openSqlSession() throws IOException {
  5. //1.读取核心配置文件
  6. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  7. //2.创建工厂对象
  8. SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
  9. //3.取出sqlSession
  10. sqlSession=factory.openSession();
  11. }
  12. @After
  13. public void closeSqlSession(){
  14. sqlSession.close();
  15. }
  16. @Test
  17. public void testGetAll(){
  18. //取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中相应的标签的功能。
  19. UsersMapper uMapper =sqlSession.getMapper(UsersMapper.class);
  20. System.out.println(uMapper.getClass());
  21. //就是在调用接口的方法,mybatis框架已经为我们把功能代理出来了
  22. List<Users> list = uMapper.getAll();
  23. list.forEach(users -> System.out.println(users));
  24. }
  25. }

7.完成增删改查

用户的更新

  1. //用户的更新
  2. int update(Users users);
  1. <!--
  2. //用户的更新
  3. int update(Users users);
  4. private Integer id;
  5. private String userName;
  6. private Date birthday;
  7. private String sex;
  8. private String address;
  9. -->
  10. <update id="update" parameterType="users">
  11. update users set username=#{userName},birthday=#{birthday},sex=#{sex},address=#{address}
  12. where id=#{id}
  13. </update>
  1. public class MyTest {
  2. SqlSession sqlSession;
  3. UsersMapper uMapper;
  4. //日期格式化刷子
  5. SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
  6. @Before
  7. public void openSqlSession() throws IOException {
  8. //1.读取核心配置文件
  9. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  10. //2.创建工厂对象
  11. SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
  12. //3.取出sqlSession
  13. sqlSession=factory.openSession();
  14. //取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中相应的标签的功能。
  15. uMapper =sqlSession.getMapper(UsersMapper.class);
  16. }
  17. @After
  18. public void closeSqlSession(){
  19. sqlSession.close();
  20. }
  21. @Test
  22. public void testUpdate() throws ParseException {
  23. Users u = new Users(7,"haha",sf.parse("2000-01-01"),"2","下海");
  24. int num=uMapper.update(u);
  25. //切记切记切记:手工提交事务
  26. sqlSession.commit();
  27. }
  28. }

根据主键查询

  1. //根据用户主键查询用户
  2. Users getById(Integer id);
  1. <!--
  2. //根据用户主键查询用户
  3. Users getById(Integer id);
  4. -->
  5. <select id="getById" parameterType="int" resultType="users">
  6. select id,username,birthday,sex,address
  7. from users where id=#{id};
  8. </select>
  1. /*SqlSession sqlSession;
  2. UsersMapper uMapper;
  3. 在update中被封装了
  4. */
  5. @Test
  6. public void testById(){
  7. Users u =uMapper.getById(1);
  8. System.out.println(u);
  9. }

模糊查询

  1. //模糊查询
  2. List<Users> getByName(String name);
  1. <!-- //模糊查询
  2. List<Users> getByName(String name); -->
  3. <select id="getByName" parameterType="string" resultType="users">
  4. select id,username,birthday,sex,address
  5. from users
  6. where username like '%${name}%'
  7. </select>
  1. @Test
  2. public void testGetByName(){
  3. List<Users> list =uMapper.getByName("小");
  4. list.forEach(users -> System.out.println(users));
  5. }

增加用户

  1. //增加用户
  2. int insert(Users users);
  1. <!--
  2. //增加用户
  3. int insert(Users users);
  4. -->
  5. <insert id="insert" parameterType="users">
  6. insert into users (username,birthday,sex,address) values
  7. (#{userName},#{birthday},#{sex},#{address})
  8. </insert>
  1. public void testinsert() throws ParseException {
  2. Users u = new Users("hehe",sf.parse("2001-01-01"),"2","大兴");
  3. int num=uMapper.insert(u);
  4. System.out.println(num);
  5. sqlSession.commit();
  6. }

根据id删除用户

  1. //根据主键删除用户
  2. int delete(Integer id);
  1. <!--
  2. //根据主键删除用户
  3. int delete(Integer id);
  4. -->
  5. <delete id="delete" parameterType="int">
  6. delete from users
  7. where id=#{id}
  8. </delete>
  1. @Test
  2. public void testDelete() {
  3. int num=uMapper.delete(1);
  4. System.out.println(num);
  5. sqlSession.commit();
  6. }

8.完成mapper.xml文件的优化

  1. <mappers>
  2. <!--注册mapper.xml文件
  3. <mapper class="com.bjpowernode.mapper.UsersMapper"></mapper>
  4. -->
  5. <!--批量注册-->
  6. <package name="com.bjpowernode.mapper"></package>
  7. </mappers>

4.#{}和${}

#{}占位符

传参大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问 ,防止sql注入.
#{}里如何写,看parameterType参数的类型
1)如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写.

  1. <select id="getById" parameterType="int" resultType="users"> ===>入参类型是简单类型
  2. select id,username,birthday,sex,address
  3. from users
  4. where id=#{zar} ===>随便写
  5. </select>

2)parameterType的类型是实体类的类型,则#{}里只能是类中成员变量的名称,而且区分大小写.

  1. <insert id="insert" parameterType="users" > ===>入参是实体类
  2. insert into users (username, birthday, sex, address) values(#{userName},#{birthday},#{sex},#{address}) ==>成员变量名称
  3. </insert>


${}字符串拼接或字符串替换

1)字符串拼接,一般用于模糊查询中.建议少用,因为有sql注入的风险.
也分两种情况,同样的看parameterType的类型
A. 如果parameterType的类型是简单类型,则${}里随便写,但是分版本,如果是3.5.1及以下的版本,只以写value.

  1. <select id="getByName" parameterType="string" resultType="users"> ===>入参是简单类型
  2. select id,username,birthday,sex,address
  3. from users
  4. where username like '%${zar}%' ===>随便写
  5. </select>
  1. B. 如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称.(现在已经少用)

(1)优化模糊查询

  1. C. 优化后的模糊查询(以后都要使用这种方式)
  1. <select id="getByNameGood" parameterType="string" resultType="users">
  2. select id,username,birthday,sex,address
  3. from users
  4. where username like concat('%',#{name},'%')
  5. </select>

2)字符串替换

需求:模糊地址或用户名查询
select from users where username like ‘%小%’;
select
from users where address like ‘%市%’

  1. <!--
  2. //模糊用户名和地址查询
  3. //如果参数超过一个,则parameterType不写
  4. List<Users> getByNameOrAddress(
  5. @Param("columnName") ===>为了在sql语句中使用的名称
  6. String columnName,
  7. @Param("columnValue") ===>为了在sql语句中使用的名称
  8. String columnValue);
  9. -->
  10. <select id="getByNameOrAddress" resultType="users">
  11. select id,username,birthday,sex,address
  12. from users
  13. where ${columnName} like concat('%',#{columnValue},'%') ==>此处使用的是@Param注解里的名称
  14. </select>
  1. @Test
  2. public void testGetByNameOrAddress(){
  3. List<Users> list =uMapper.getByNameOrAddress("address","市");
  4. list.forEach(users -> System.out.println(users));
  5. }

3)返回主键值

image.png
在插入语句结束后, 返回自增的主键值到入参的users对象的id属性中.

  1. <insert id="insert" parameterType="users" >
  2. <selectKey keyProperty="id" resultType="int" order="AFTER">
  3. select last_insert_id()
  4. </selectKey>
  5. insert into users (username, birthday, sex, address) values(#{userName},#{birthday},#{sex},#{address})
  6. </insert>

标签的参数详解:
keyProperty: users对象的哪个属性来接返回的主键值
resultType:返回的主键的类型
order:在插入语句执行前,还是执行后返回主键的值

UUID(补充)
这是一个全球唯一随机字符串,由36个字母数字中划线组.
UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString().replace(“-“,””).substring(20));

四、动态SQL

1.什么是动态sql
可以定义代码片断,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更为简单.

下面举的例子中:相当于省略了1=1

  1. select * from users
  2. where 1=1
  3. and sex=1
  4. and username='%小%'

sql

1):用来定义代码片断,可以将所有的列名,或复杂的条件定义为代码片断,供使用时调用.
2):用来引用定义的代码片断.

  1. <!--定义代码片断-->
  2. <sql id="allColumns">
  3. id,username,birthday,sex,address
  4. </sql>
  5. //引用定义好的代码片断
  6. <select id="getAll" resultType="users" >
  7. select <include refid="allColumns"></include>
  8. from users
  9. </select>

if和where

:进行条件判断
test条件判断的取值可以是实体类的成员变量,可以是map的key,可以是@Param注解的名称.
:进行多条件拼接,在查询,删除,更新中使用.

  1. <select id="getByCondition" parameterType="users" resultType="users">
  2. select <include refid="allColumns"></include>
  3. from users
  4. <where>
  5. <if test="userName != null and userName != ''">
  6. and username like concat('%',#{userName},'%')
  7. </if>
  8. <if test="birthday != null">
  9. and birthday = #{birthday}
  10. </if>
  11. <if test="sex != null and sex != ''">
  12. and sex = #{sex}
  13. </if>
  14. <if test="address != null and address != ''">
  15. and address like concat('%',#{address},'%')
  16. </if>
  17. </where>
  18. </select>
  1. @Test
  2. public void testGetByCondition()throws Exception{
  3. Users u = new Users();
  4. //如果不赋值,则是查找所有
  5. u.setUserName("小");
  6. u.setSex("1");
  7. u.setAddress("市");
  8. u.setBirthday(sf.parse("2002-01-19"));
  9. List<Users> list = usersMapper.getByCondition(u);
  10. list.forEach(users -> System.out.println(users));
  11. }

set

:有选择的进行更新处理,至少更新一列.能够保证如果没有传值进来,则数据库中的数据保持不变.

  1. <update id="updateBySet" parameterType="users">
  2. update users
  3. <set>
  4. <if test="userName != null and userName != ''">
  5. username = #{userName},
  6. </if>
  7. <if test="birthday != null">
  8. birthday = #{birthday},
  9. </if>
  10. <if test="sex != null and sex != ''">
  11. sex = #{sex},
  12. </if>
  13. <if test="address != null and address != ''">
  14. address =#{address} ,
  15. </if>
  16. </set>
  17. where id = #{id}
  18. </update>
  1. Test
  2. public void testUpdateSet()throws Exception{
  3. // Users u = new Users("哈哈",new Date(),"1","北京亦庄大兴");
  4. //Users u = new Users(3,"不知道",sf.parse("1998-08-08"),"2","北京亦庄大兴888");
  5. Users u = new Users();
  6. u.setId(2);
  7. u.setUserName("认识张三不");
  8. //u.setSex("2");
  9. //u.setBirthday(sf.parse("2000-01-01"));
  10. int num = usersMapper.updateBySet(u);
  11. //切记切记:必须提交事务
  12. sqlSession.commit();
  13. System.out.println(num);
  14. }

foreach

:用来进行循环遍历,完成循环条件查询,批量删除,批量增加,批量更新.

  1. <select id="getByIds" resultType="users">
  2. select <include refid="allColumns"></include>
  3. from users
  4. where id in
  5. <foreach collection="array" item="id" separator="," open="(" close=")">
  6. #{id}
  7. </foreach>
  8. </select>

参数详解:
collection:用来指定入参的类型,如果是List集合,则为list,如果是Map集合,则为map,如果是数组,则为array.
item:每次循环遍历出来的值或对象
separator:多个值或对象或语句之间的分隔符
open:整个循环外面的前括号
close:整个循环外面的后括号

  1. <delete id="deleteBatch" >
  2. delete from users
  3. where id in
  4. <foreach collection="array" item="id" separator="," open="(" close=")">
  5. #{id}
  6. </foreach>
  7. </delete>
  1. <insert id="insertBatch">
  2. insert into users(username, birthday, sex, address) values
  3. <foreach collection="list" item="u" separator="," >
  4. (#{u.userName},#{u.birthday},#{u.sex},#{u.address})
  5. </foreach>
  6. </insert>

指定参数位置

如果入参是多个,可以通过指定参数位置进行传参. 是实体包含不住的条件.实体类只能封装住成员变量的条件.如果某个成员变量要有区间范围内的判断,或者有两个值进行处理,则实体类包不住.
例如:查询指定日期范围内的用户信息.

  1. <select id="getByBirthday" resultType="users">
  2. select <include refid="allColumns"></include>
  3. from users
  4. where birthday between #{arg0} and #{arg1}
  5. </select>

入参是map(重点掌握)

如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更明确.

  1. <!--
  2. //入参是map
  3. List<Users> getByMap(Map map);
  4. #{birthdayBegin}:就是map中的key
  5. -->
  6. <select id="getByMap" resultType="users" >
  7. select <include refid="allColumns"></include>
  8. from users
  9. where birthday between #{birthdayBegin} and #{birthdayEnd}
  10. </select>
  1. 测试类中
  2. @Test
  3. public void testGetByMap() throws ParseException {
  4. Date begin = sf.parse("1999-01-01");
  5. Date end = sf.parse("1999-12-31");
  6. Map map = new HashMap<>();
  7. map.put("birthdayBegin",begin);
  8. map.put("birthdayEnd", end);
  9. List<Users> list = uMapper.getByMap(map);
  10. list.forEach(users -> System.out.println(users));
  11. }

返回值是map

5---返回多个值.png
如果返回的数据实体类无法包含,可以使用map返回多张表中的若干数据.返回后这些数据之间没有任何关系.就是Object类型.返回的map的key就是列名或别名.

  1. <!--
  2. //返回值是map(一行)
  3. Map getReturnMap(Integer id);
  4. -->
  5. <select id="getReturnMap" parameterType="int" resultType="map">
  6. select username name,address add <!--name是username的别名,add是address的别名-->
  7. from users
  8. where id=#{id}
  9. </select>
  10. <!--
  11. //返回多行的map
  12. List<Map> getMulMap();
  13. -->
  14. <select id="getMulMap" resultType="map">
  15. select username,address
  16. from users
  17. </select>

测试类

  1. @Test
  2. public void testGetReturnMapOne(){
  3. Map<String,Object> map = mapper.getReturnMapOne(7);
  4. System.out.println(map);
  5. System.out.println(map.get("name"));
  6. }
  1. @Test
  2. public void testGetReturnMap(){
  3. List<Map<String,Object>> list = mapper.getReturnMap();
  4. list.forEach(map-> System.out.println(map));
  5. }

使用别名进行成员变量和列明的映射

实体类中: id,name
数据库中:bookid,bookname

  1. <mapper namespace="com.bjpowernode.mapper.BookMapper">
  2. <!--
  3. 查询全部图书
  4. List<Book> getAll();
  5. -->
  6. <!--使用resultMap手工完成映射--> <!--这个book是泛型中的类型-->
  7. <resultMap id="bookmap" type="book">
  8. <!--主键绑定-->
  9. <id property = "id" column="bookid"></id>
  10. <!--非主键绑定-->
  11. <result property="name" column="bookname"></result>
  12. </resultMap>
  13. <select id="getAll" resultMap="bookmap">
  14. select bookid,bookname
  15. from book
  16. </select>
  17. </mapper>

五、表的关联关系

一对多关联关系

客户和订单就是典型的一对多关联关系.
一个客户名下可以有多个订单.
客户表是一方,订单表是多方.客户一中持有订单的集合.
使用一对多的关联关系,可以满足查询客户的同时查询该客户名下的所有订单.

  1. <mapper namespace="com.bjpowernode.mapper.CustomerMapper">
  2. <!--
  3. //根据客户的id查询客户所有信息并同时查询该客户名下的所有订单
  4. Customer getById(Integer id)
  5. 实体类:
  6. //customer表中的三个列
  7. private Integer id;
  8. private String name;
  9. private Integer age;
  10. //该客户名下的所有订单的集合
  11. private List<Orders> ordersList;
  12. -->
  13. <resultMap id="customermap" type="customer">
  14. <!--主键绑定-->
  15. <id property="id" column="cid"></id>
  16. <!--非主键绑定-->
  17. <result property="name" column="name"></result>
  18. <result property="age" column="age"></result>
  19. <!--多出来的一咕噜绑定ordersList
  20. Orders实体类:
  21. private Integer id;
  22. private String orderNumber;
  23. private Double orderPrice;
  24. -->
  25. <collection property="ordersList" ofType="orders">
  26. <!--主键绑定-->
  27. <id property="id" column="oid"></id>
  28. <!--非主键绑定-->
  29. <result property="orderNumber" column="orderNumber"></result>
  30. <result property="orderPrice" column="orderPrice"></result>
  31. </collection>
  32. </resultMap>
  33. <select id="getById" parameterType="int" resultMap="customermap">
  34. select c.id cid,name,age,o.id oid,orderNumber,orderPrice,customer_id
  35. from customer c left join orders o on c.id = o.customer_id
  36. where c.id=#{id}
  37. </select>
  38. </mapper>

多对一关联关系.

订单和客户就是多对一关联.
站在订单的方向查询订单的同时将客户信息查出.
订单是多方,会持有一方的对象.客户是一方.

  1. <mapper namespace="com.bjpowernode.mapper.OrdersMapper">
  2. <!--
  3. //根据主键查询订单,并同时查询下此订单的客户信息
  4. Orders getById(Integer id);
  5. -->
  6. <!--
  7. 手工绑定数据
  8. 实体类
  9. private Integer id;
  10. private String orderNumber;
  11. private Double orderPrice;
  12. //关联下此订单的客户信息,多方持有一方的对象
  13. private Customer customer;
  14. -->
  15. <resultMap id="ordersmap" type="orders">
  16. <!--主键绑定-->
  17. <id property="id" column="oid"></id>
  18. <!--非主键绑定-->
  19. <result property="orderNumber" column="orderNumber"></result>
  20. <result property="orderPrice" column="orderPrice"></result>
  21. <!--多出来的一咕噜绑定
  22. private Integer id;
  23. private String name;
  24. private Integer age;
  25. //该客户名下的所有订单的集合,一方持有多方的集合
  26. private List<Orders> ordersList; //不用管
  27. -->
  28. <association property="customer" javaType="customer">
  29. <id property="id" column="cid"></id>
  30. <result property="name" column="name"></result>
  31. <result property="age" column="age"></result>
  32. </association>
  33. </resultMap>
  34. <select id="getById" parameterType="int" resultMap="ordersmap">
  35. select o.id oid,orderNumber,orderPrice,customer_id,c.id cid,name,age
  36. from orders o inner join customer c on o.customer_id = c.id
  37. where o.id=#{id}
  38. </select>
  39. </mapper>

24.一对一关联
25.多对多关联
总结:无论是什么关联关系,如果某方持有另一方的集合,则使用标签完成映射,如果某方持有另一方的对象,则使用标签完成映射。

六、事务

多个操作同时完成,或同时失败称为事务处理.
事务有四个特性:一致性,持久性,原子性,隔离性.

下订单的业务:
1)订单表中完成增加一条记录的操作
2)订单明细表中完成N条记录的增加
3)商品数据更新(减少)
4)购物车中已支付商品删除
5)用户积分更新(增加)

在MyBatis框架中设置事务
===>程序员自己控制处理的提交和回滚

可设置为自动提交
sqlSession = factory.openSession(); ===>默认是手工提交事务,设置为false也是手工提交事务,如果设置为true,则为自动提交.
sqlSession = factory.openSession(true); ===>设置为自动提交,在增删改后不需要commit();

七、缓存

MyBatis框架提供两级缓存,一级缓存和二级缓存.默认开启一级缓存.

缓存就是为了提高查询效率.

使用缓存后,查询的流程:
查询时先到缓存里查,如果没有则查询数据库,放缓存一份,再返回客户端.下次再查询的时候直接从缓存返回,不再访问数据库.如果数据库中发生commit()操作,则清空缓存.
image.png

一级缓存使用的是SqlSession的作用域,同一个sqlSession共享一级缓存的数据.
二级缓存使用的是mapper的作用域,不同的sqlSession只要访问的同一个mapper.xml文件,则共享二级缓存作用域.

八、什么是ORM

ORM(Object Relational Mapping):对象关系映射
MyBatis框架是ORM非常优秀的框架.
java语言中以对象的方式操作数据,存到数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换称为映射.整个这套操作就是ORM.

持久化的操作:将对象保存到关系型数据库中 ,将关系型数据库中的数据读取出来以对象的形式封装

MyBatis是持久化层优秀的框架.
image.png
添加:resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型

  1. <select id="getAll" resultType="com.bjpowernode.pojo.Student" >
  2. select id,name,email,age
  3. from student
  4. </select>

映射.png
image.png

  1. public class Users implements java.io.Serializable {
  2. private Long id;
  3. private String name;
  4. private String password;
  5. private String telephone;
  6. private String username;
  7. private String isadmin;
  8. private Set houses = new HashSet(0);
  9. set()….get()……
  10. }
  1. create table USERS
  2. (
  3. ID NUMBER(10) primary key,
  4. NAME VARCHAR2(50),
  5. PASSWORD VARCHAR2(50),
  6. TELEPHONE VARCHAR2(15),
  7. USERNAME VARCHAR2(50),
  8. ISADMIN VARCHAR2(5)
  9. );
  1. <collection property="orders" ofType="order">
  2. <id property="id" column="oid"></id>
  3. <result property="orderNumber" column="ordernumber"></result>
  4. <result property="orderPrice" column="orderprice"></result>
  5. </collection>

MyBatis框架结构

image.png