MyBatis知识点

一、MyBatis简介

1.1 框架概念

框架,就是软件的半成品,完成了软件开发过程中的通用操作,程序员只需很少或者不用进行加工就能够实现特定的功能,从而简化开发人员在软件开发中的步骤,提高开发效率。

1.2 常用框架

  • MVC框架:简化了Servlet的开发步骤
    • Struts
    • Struts2
    • SpringMVC
  • 持久层框架:完成数据库操作的框架
    • apache DBUtils
    • Hibernate
    • Spring JPA
    • MyBatis
    • EJB3.0
  • 胶水框架:Spring

SSM Spring SpringMVC MyBatis

SSH Spring Struts2 Hibernate

1.3 MyBatis介绍

MyBatis是一个半自动ORM框架

ORM(Object Relational Mapping)对象关系映射,将Java中的一个对象与数据表中一行记录一一对应。

ORM框架提供了实体类与数据表的映射关系,通过映射文件的配置,实现对象的持久化。

  • MyBatis的前身是iBatis,iBatis是Apache软件基金会提供的一个开源项目
  • 2010年iBatis迁移到Google code,正式更名为MyBatis
  • 2013年迁移到Github托管
  • MyBatis特点:
    • 支持自定义SQL、存储过程
    • 对原有的JDBC进行了封装,几乎消除了所有JDBC代码,让开发者只需关注SQL本身
    • 支持XML和注解配置方式自定完成ORM操作,实现结果映射

二、MyBatis框架部署

框架部署,就是将框架引入到我们的项目中

2.1 创建Maven项目

  • Java工程
  • Web工程

2.2 在项目中添加MyBatis依赖

  • 在pom.xml中添加依赖

    • mybatis
    • mysql driver
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version>
    </dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version>
    </dependency>
    

2.3 创建MyBatis配置文件

  • 创建自定义模板:选择resources----右键New----Edit File Templates

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P4JExyWD-1639493777615)(imgs/1616144597211.png)]

  • 在resources中创建名为mybatis-config.xml的文件

  • mybatis-config.xml文件配置数据库连接信息

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!-- 在environments配置数据库连接信息 --><!-- 在environments标签中可以定义多个environment标签,每个environment标签可以定义一套连接配置 --><!-- default属性,用来指定使用哪个environment标签 --><environments default="mysql"><environment id="mysql"><!--transactionManager标签用于配置数据库管理方式--><transactionManager type="JDBC"></transactionManager><!--dataSource标签就是用来配置数据库连接信息 --><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/db_2010_fmwy?characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="admin123"/></dataSource></environment></environments></configuration>
    

三、MyBatis框架使用

案例:学生信息的数据库操作

3.1 创建数据表

tb_students
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FppE0G06-1639493777619)(imgs/1616145569298.png)]

3.2 创建实体类

Student.java
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GSFZ4RV3-1639493777619)(imgs/1616145876310.png)]

3.3 创建DAO接口,定义操作方法

StudentDAO.java
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H2R7Xmra-1639493777621)(imgs/1616147015300.png)]

3.4 创建DAO接口的映射文件

  • resources目录下,新建名为mappers文件夹
  • mappers中新建名为StudentMapper.xml的映射文件(根据模板创建)
  • 在映射文件中对DAO中定义的方法进行实现:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper文件相当于DAO接口的‘实现类’,namespace属性要指定`实现`DAO接口的全限定名-->
<mapper namespace="com.qfedu.dao.StudentDAO"><insert id="insertStudent">insert into tb_students(stu_num,stu_name,stu_gender,stu_age)values(#{stuNum},#{stuName},#{stuGender},#{stuAge})</insert><delete id="deleteStudent">delete from tb_students where stu_num=#{stuNum}</delete></mapper>

3.5 将映射文件添加到主配置文件

mybatis-config.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q0lf9JK0-1639493777621)(imgs/1616146926729.png)]

四、单元测试

4.1 添加单元测依赖

<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version>
</dependency>

4.2 创建单元测试类

在被测试类名后alt+insert — 选择Test
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VMGaSWhm-1639493777622)(imgs/1616147095936.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2uvbBYCd-1639493777623)(imgs/1616147180562.png)]

4.3 测试代码

package com.qfedu.dao;import com.qfedu.pojo.Student;
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 static org.junit.Assert.*;public class StudentDAOTest {@org.junit.Testpublic void insertStudent() {try {//加载mybatis配置文件InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//会话工厂SqlSessionFactory factory = builder.build(is);//会话(连接)SqlSession sqlSession = factory.openSession();//通过会话获取DAO对象StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);//测试StudentDAO中的方法int i = studentDAO.insertStudent(new Student(0, "10001", "张三", "男", 21));//需要手动提交sqlSession.commit();System.out.println(i);} catch (IOException e) {e.printStackTrace();}}@org.junit.Testpublic void deleteStudent() {}
}

五、MyBatis的CRUD操作

案例:学生信息的增删查改

5.1 添加操作

5.2 删除操作

根据学号删除一条学生信息

  • 在StudentDAO中定义删除方法
StudentDAO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HCObnCRl-1639493777624)(imgs/1616463209812.png)]
  • 在StudentMapper.xml中对接口方法进行“实现”
StudentMapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AbKpsHuZ-1639493777625)(imgs/1616463282187.png)]
  • 测试:在StudentDAO的测试类中添加测试方法
StudentDAOTest
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hUYCWgfM-1639493777626)(imgs/1616464771784.png)]

5.3 修改操作

根据学生学号,修改其他字段信息

  • 在StudentDAO接口中定义修改方法
StudentDAO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-McpeRIEg-1639493777626)(imgs/1616465607290.png)]
  • 在StudentMapper.xml中“实现”接口中定义的修改方法
StudentMapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-14p5zRZL-1639493777627)(imgs/1616465639080.png)]
  • 单元测试
StudentDAOTest
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xYIcjRfO-1639493777628)(imgs/1616465667657.png)]

5.4 查询操作-查询所有

  • 在StudentDAO接口定义操作方法
StudentDAO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1oDFXZF6-1639493777629)(imgs/1616467216382.png)]
  • 在StudentMapper.xml中“实现”DAO中定义的方法
StudentMapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGwmF4HX-1639493777629)(imgs/1616467314082.png)]
  • 单元测试
StudentDAOTest
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xci0oBM2-1639493777630)(imgs/1616467336432.png)]

5.5 查询操作-查询一条记录

根据学号查询一个学生信息

  • 在StudentDAO接口中定义方法
StudentDAO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZfqOcjhG-1639493777631)(imgs/1616469113754.png)]
  • 在StudentDAOMapper.xml中配置StudentDAO接口的方法实现——SQL
StudentDAOMapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fwMetDD6-1639493777631)(imgs/1616469142604.png)]
  • 单元测试
StudentDAOTest
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VBclfidK-1639493777638)(imgs/1616469154258.png)]

5.6 查询操作-多参数查询

分页查询(参数 start , pageSize)

  • 在StudentDAO中定义操作方法,如果方法有多个参数,使用@Param注解声明参数的别名
StudentDAO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yIXlmzgc-1639493777638)(imgs/1616470534343.png)]
  • 在StudentMapper.xml配置sql时,使用#{别名}获取到指定的参数
StudentMapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HI4IVPTg-1639493777639)(imgs/1616470612608.png)]

注意 如果DAO操作方法没有通过@Param指定参数别名,在SQL中也可以通过arg0,arg1...或者param1,param2,...获取参数

5.7 查询操作-查询总记录数

  • 在StudentDAO接口中定义操作方法
StudentDAO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JWtfTDQ5-1639493777639)(imgs/1616471133486.png)]
  • 在StudentMapper.xml配置sql,通过resultType指定当前操作的返回类型为int
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GIQtkvSD-1639493777640)(imgs/1616471056064.png)]

5.8 添加操作回填生成的主键

  • StduentMapper.xml的添加操作标签——insert
<!-- useGeneratedKeys 设置添加操作是否需要回填生成的主键 -->
<!-- keyProperty 设置回填的主键值赋值到参数对象的哪个属性 -->
<insert id="insertStudent" useGeneratedKeys="true" keyProperty="stuId">insert into tb_students(stu_num, stu_name, stu_gender, stu_age)values (#{stuNum}, #{stuName}, #{stuGender}, #{stuAge})
</insert>

六、MyBatis工具类封装

  • MyBatisUtil
public class MyBatisUtil {private static SqlSessionFactory factory;private static final ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>();static{try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();factory = builder.build(is);} catch (IOException e) {e.printStackTrace();}}public static SqlSessionFactory getFactory(){return factory;}public static SqlSession getSqlSession(){SqlSession sqlSession = local.get();if(sqlSession == null ){sqlSession = factory.openSession();local.set(sqlSession);}return sqlSession;}public static <T extends Object> T getMapper(Class<T> c){SqlSession sqlSession = getSqlSession();return sqlSession.getMapper(c);}}

七、事务管理

SqlSession 对象

  • getMapper(DAO.class) : 获取Mapper(DAO接口的实例)
  • 事务管理

7.1 手动提交事务

  • sqlSession.commit();提交事务
  • sqlSession.rollback();事务回滚

测试类中进行事务管理

@Test
public void insertStudent() {SqlSession sqlSession = MyBatisUtil.getSqlSession();//1.当我们获取sqlSession对象时,就默认开启了事务try{//通过会话获取DAO对象StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);//测试StudentDAO中的方法Student student = new Student(0, "10005", "Lily", "女", 21);int i = studentDAO.insertStudent(student);//2.操作完成并成功之后,需要手动提交sqlSession.commit();}catch (Exception e){//3.当操作出现异常,调用rollback进行回滚sqlSession.rollback();}
}

业务逻辑层手动事务管理

public class StudentServiceImpl implements StudentService {public boolean addStudent(Student student) {boolean b = false;SqlSession sqlSession = MyBatisUtil.getSqlSession();try{StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);int i = studentDAO.insertStudent(student);b = i>0;sqlSession.commit();}catch (Exception e){sqlSession.rollback();}return b;}
}

7.2 自动提交事务

通过SqlSessionFactory调用openSession方法获取SqlSession对象时,可以通过参数设置事务是否自动提交:

  • 如果参数设置为true,表示自定提交事务: factory.openSession(true);

  • 如果参数设置为false,或者不设置参数,表示手动提交:factory.openSession();/factory.openSession(false);

MyBatisUtil优化

public class MyBatisUtil {private static SqlSessionFactory factory;private static final ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>();static{try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();factory = builder.build(is);} catch (IOException e) {e.printStackTrace();}}public static SqlSessionFactory getFactory(){return factory;}private static SqlSession getSqlSession(boolean isAutoCommit){SqlSession sqlSession = local.get();if(sqlSession == null ){sqlSession = factory.openSession(isAutoCommit);local.set(sqlSession);}return sqlSession;}//手动事务管理public static SqlSession getSqlSession(){return getSqlSession(false);}//自动事务提交public static <T extends Object>T getMapper(Class<T> c){SqlSession sqlSession = getSqlSession(true);return sqlSession.getMapper(c);}}

测试操作

@Test
public void testDeleteStudent() {StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class);int i = studentDAO.deleteStudent("10001");
}

业务逻辑层自动事务管理

public class StudentServiceImpl implements StudentService {private StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class);public boolean addStudent(Student student) {int i = studentDAO.insertStudent(student);boolean b = i>0;return b;}
}

八、MyBatis主配置文件

mybatis-config.xml 是MyBatis框架的主配置文件,只要用于配置MyBatis数据源及属性信息

8.1 properties标签

用于设置键值对,或者加载属性文件

  • 在resources目录下创建jdbc.properties文件,配置键值对如下:
mysql_driver=com.mysql.jdbc.Driver
mysql_url=jdbc:mysql://localhost:3306/db_2010_fmwy?characterEncoding=utf-8
mysql_username=root
mysql_password=admin123
  • 在mybatis-config.xml中通过properties标签引用jdbc.properties文件;引入之后,在配置environment时可以直接使用jdbc.properties的key获取对应的value
mybatis-config.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DqVD8IaY-1639493777640)(imgs/1616482928813.png)]

8.2 settings标签

<!--设置mybatis的属性-->
<settings><!-- 启动二级缓存--><setting name="cacheEnabled" value="true"/><!-- 启动延迟加载 --><setting name="lazyLoadingEnabled" value="true"/>
</settings>

8.3 typeAliases标签

<!--typeAliases标签用于给实体类取别名,在映射文件中可以直接使用别名来替代实体类的全限定名-->
<typeAliases><typeAlias type="com.qfedu.pojo.Student" alias="Student"></typeAlias><typeAlias type="com.qfedu.pojo.Book" alias="Book"></typeAlias>
</typeAliases>

8.4 plugins标签

<!--plugins标签,用于配置MyBatis插件(分页插件)-->
<plugins><plugin interceptor=""></plugin>
</plugins>

8.5 environments标签

<!-- 在environments配置数据库连接信息 -->
<!-- 在environments标签中可以定义多个environment标签,每个environment标签可以定义一套连接配置 -->
<!-- default属性,用来指定使用哪个environment标签 -->
<environments default="mysql"><!--  environment 标签用于配置数据库连接信息  --><environment id="mysql"><!--transactionManager标签用于配置数据库管理方式type="JDBC"  可以进行事务的提交和回滚操作type="MANAGED" 依赖容器完成事务管理,本身不进行事务的提交和回滚操作 --><transactionManager type="JDBC"></transactionManager><!--dataSource标签就是用来配置数据库连接信息 POOLED|UNPOOLED --><dataSource type="POOLED"><property name="driver" value="${mysql_driver}"/><property name="url" value="${mysql_url}"/><property name="username" value="${mysql_username}"/><property name="password" value="${mysql_password}"/></dataSource></environment></environments>

8.6 mappers标签

加载映射配置(映射文件、DAO注解)

<!--mappers标签用于载入映射文件-->
<mappers><mapper resource="mappers/StudentMapper.xml"></mapper>
</mappers>

九、映射文件

9.1 MyBatis Mapper初始化

XML文件解析:读取xml文件中的标签配置封装到Java对象中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eFmhNoJc-1639493777641)(imgs/1616487875112.png)]

9.2 mapper根标签

mapper文件相当于DAO接口的‘实现类’,namespace属性要指定实现DAO接口的全限定名

9.3 insert标签

声明添加操作(sql: insert …)

常用属性

id属性,绑定对应DAO接口中的方法

parameterType属性,用以指定接口中对应方法的参数类型(可省略)

useGeneratedKeys属性, 设置添加操作是否需要回填生成的主键

keyProperty属性,指定回填的id设置到参数对象中的哪个属性

timeout属性,设置此操作的超时时间,如果不设置则一直等待

主键回填

<insert id="insertStudent" useGeneratedKeys="true" keyProperty="stuId">insert into tb_students(stu_num, stu_name, stu_gender, stu_age)values (#{stuNum}, #{stuName}, #{stuGender}, #{stuAge})
</insert>
<insert id="insertStudent" ><selectKey keyProperty="stuId" resultType="java.lang.Integer">select last_insert_id()</selectKey>insert into tb_students(stu_num, stu_name, stu_gender, stu_age)values (#{stuNum}, #{stuName}, #{stuGender}, #{stuAge})
</insert>

9.4 delete标签

声明删除操作

9.5 update标签

声明修改操作

9.6 select标签

声明查询操作

  • id属性, 指定绑定方法的方法名

  • parameterType属性,设置参数类型

  • resultType属性,指定当前sql返回数据封装的对象类型(实体类)

  • resultMap属性,指定从数据表到实体类的字段和属性的对应关系

  • useCache属性,指定此查询操作是否需要缓存

  • timeout属性,设置超时时间

9.7 resultMap标签

<!-- resultMap标签用于定义实体类与数据表的映射关系(ORM) -->
<resultMap id="studentMap" type="Student"><id column="sid" property="stuId"/><result column="stu_num" property="stuNum"/><result column="stu_name" property="stuName"/><result column="stu_gender" property="stuGender"/><result column="stu_age" property="stuAge"/>
</resultMap>

9.8 cache标签

设置当前DAO进行数据库操作时的缓存属性设置

<cache type="" size="" readOnly="false"/>

9.9 sql和include

SQL片段

<sql id="wanglaoji">sid , stu_num , stu_name , stu_gender , stu_age</sql><select id="listStudents" resultMap="studentMap">select <include refid="wanglaoji"/> from tb_students
</select>

十、分页插件

分页插件是一个独立于MyBatis框架之外的第三方插件;

10.1 添加分页插件的依赖

PageHelper

 <!-- pagehelper分页插件 -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version>
</dependency>

10.2 配置插件

在mybatis的主配置文件mybatis-config.xml中通过plugins标签进行配置

<!--plugins标签,用于配置MyBatis插件(分页插件)-->
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

10.3 分页实例

对学生信息进行分页查询

@Test
public void testListStudentsByPage() {StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class); //sqlSessionPageHelper.startPage(2,4);List<Student> students = studentDAO.listStudents();PageInfo<Student> pageInfo = new PageInfo<Student>(students);//pageInfo中就包含了数据及分页信息
}

带条件分页

@Test
public void testListStudentsByPage() {StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class); //sqlSessionPageHelper.startPage(2,4);//List<Student> students = studentDAO.listStudents();List<Student> list = studentDAO.listStudentsByGender("女");PageInfo<Student> pageInfo = new PageInfo<Student>(list);//pageInfo中就包含了数据及分页信息
}

十一、关联映射

11.1 实体关系

实体——数据实体,实体关系指的就是数据与数据之间的关系

例如:用户和角色、房屋和楼栋、订单和商品

实体关系分为以下四种:

一对一关联

实例:人和身份证、学生和学生证、用户基本信息和详情

数据表关系:

  • 主键关联(用户表主键 和详情主键相同时,表示是匹配的数据)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lF3JppTg-1639493777641)(imgs/1616550990633.png)]

  • 唯一外键关联

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kQgWLt5-1639493777642)(imgs/1616551159843.png)]

一对多关联多对一关联

实例:

  • 一对多: 班级和学生 、 类别和商品、楼栋和房屋
  • 多对一:学生和班级 、 商品和类别

数据表关系:

  • 在多的一端添加外键和一的一段进行关联

多对多关联

实例:用户和角色、角色和权限、房屋和业主、学生和社团、订单和商品

数据表关系:建立第三张关系表添加两个外键分别与两张表主键进行关联

用户(user_id) 用户角色表(uid,rid) 角色(role_id)

11.2 创建项目,部署MyBatis框架

  • 创建web项目(maven)

    <!-- 添加web依赖 -->
    <dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope>
    </dependency>
    <dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope>
    </dependency>
    
  • 部署MyBatis框架

    • 添加依赖
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version>
    </dependency>
    
    • 配置文件
    • 帮助类
    public class MyBatisUtil {private static SqlSessionFactory factory;private static final ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>();static{try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");factory = new SqlSessionFactoryBuilder().build(is);} catch (IOException e) {e.printStackTrace();}}public static SqlSessionFactory getSqlSessionFactory(){return factory;}public static SqlSession getSqlSession(boolean isAutoCommit){SqlSession sqlSession = local.get();if(sqlSession == null){sqlSession = factory.openSession(isAutoCommit);local.set(sqlSession);}return sqlSession;}public static SqlSession getSqlSession(){return getSqlSession(false);}public static <T extends  Object>T getMapper(Class<T> c){SqlSession sqlSession = getSqlSession(true);return sqlSession.getMapper(c);}}
    

11.3 一对一关联

实例:用户—详情

11.3.1 创建数据表
-- 用户信息表
create table users(user_id int primary key auto_increment,user_name varchar(20) not null unique,user_pwd varchar(20) not null,user_realname varchar(20) not null,user_img varchar(100) not null
);-- 用户详情表
create table details(detail_id int primary key auto_increment,user_addr varchar(50) not null,user_tel char(11) not null,user_desc varchar(200),uid int not null unique-- constraint FK_USER foreign key(uid) references users(user_id)
);
11.3.2 创建实体类
  • User

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class User {private int userId;private String userName;private String userPwd;private String userRealname;private String userImg;
    }
    
  • Detail

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class Detail {private int detailId;private String userAddr;private String userTel;private String userDesc;private int userId;
    }
    
11.3.3 添加操作(事务)
测试代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EQ0GrcR5-1639493777642)(imgs/1616558872585.png)]
11.3.4 一对一关联查询

在查询用户的同时关联查询出与之对应的详情

实体

UserDetail
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7O8YTeN4-1639493777643)(imgs/1616557527886.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4guaBShg-1639493777644)(imgs/1616557509389.png)]

映射文件

连接查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VLVqCWzx-1639493777644)(imgs/1616558061073.png)]
子查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rp27lso2-1639493777645)(imgs/1616558696902.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JcX1ZueX-1639493777645)(imgs/1616558739190.png)]

11.4 一对多关联

案例:班级(1)—学生(n)

11.4.1 创建数据表
-- 创建班级信息表
create table classes(cid int primary key auto_increment,cname varchar(30) not null unique,cdesc varchar(100)
);-- 创建学生信息表
create table students(sid char(5) primary key,sname varchar(20) not null,sage int not null,scid int not null
);
11.4.2 创建实体类
ClazzStudent
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9UKos2PN-1639493777646)(imgs/1616566868757.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bubopJKg-1639493777646)(imgs/1616566709567.png)]
11.4.3 关联查询

当查询一个班级的时候, 要关联查询出这个班级下的所有学生

连接查询

连接查询映射配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IX7Z9twQ-1639493777647)(imgs/1616567949549.png)]

子查询

子查询映射配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rXvcuBMD-1639493777648)(imgs/1616568410749.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TNAheVr2-1639493777648)(imgs/1616568443022.png)]

11.5 多对一关联

实例:学生(n)—班级(1)

当查询一个学生的时候,关联查询这个学生所在的班级信息

11.5.1 创建实体类
StudentClazz
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHLhsn1S-1639493777649)(imgs/1616568763050.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWjmY7v3-1639493777649)(imgs/1616568809974.png)]
11.5.2 关联查询

连接查询

连接查询映射配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bLeWPLcu-1639493777650)(imgs/1616569488794.png)]

子查询

子查询映射配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ro5YETEW-1639493777650)(imgs/1616569897430.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AdruQhxF-1639493777651)(imgs/1616569932235.png)]

11.6 多对多关联

案例:学生(m)—课程(n)

11.6.1 创建数据表
-- 学生信息表(如上)
-- 课程信息表
create table courses(course_id int primary key auto_increment,course_name varchar(50) not null
);
-- 选课信息表/成绩表(学号、课程号、成绩)
create table grades(sid char(5) not null,cid int not null,score int not null
);
11.6.2 关联查询

查询学生时,同时查询学生选择的课程

StudentCourse
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziu9JqnZ-1639493777651)(imgs/1616577612042.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jAn7ebCi-1639493777652)(imgs/1616577631853.png)]

根据课程编号查询课程时,同时查询选择了这门课程的学生

StudentCourse
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DIVBZMjd-1639493777652)(imgs/1616577675018.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Y5IQBNu-1639493777653)(imgs/1616577785188.png)]
连接查询映射配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZEw21kXy-1639493777653)(imgs/1616578573302.png)]
子查询映射配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cJXyjnVq-1639493777654)(imgs/1616579097777.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZO9RVUrd-1639493777654)(imgs/1616579157655.png)]

十二、动态SQL

交友网:珍爱网、百合网 筛选心仪对象 性别 年龄 城市 身高

电商:淘宝、京东 筛选商品 羽毛球拍 品牌 价格

​ 方江鹏 性别 女 select * from members where gender=‘女’

​ 罗彪 性别 女 年龄 18-23 select * from members where gender=‘女’ and age >=18 and age <=23

​ 张三 年龄 城市 select * from members where age >=18 and age <=23 and city=’’

用户的筛选条件不同,我们完成筛选执行的SQL也不一样;我们可以通过穷举来一一的完成不同条件的筛选,但是这种实现思路过于繁琐和复杂,MyBatis就提供了动态SQL的配置方式来实现多条件查询。

12.1 什么是动态SQL?

根据查询条件动态完成SQL的拼接

12.2 动态SQL使用案例

案例:心仪对象搜索

12.2.1 创建数据表
create table members(member_id int primary key auto_increment,member_nick varchar(20) not null unique,member_gender char(2) not null,member_age int not null,member_city varchar(30) not null
);
12.2.2 创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Member {private int memberId;private String memberNick;private String memberGender;private int memberAge;private String memberCity;
}
12.2.3 创建DAO接口

在DAO接口中定义一个多条件查询的方法

public interface MemberDAO {//在多条件查询中,如果查询条件不确定,可以直接使用HashMap作为参数//优点:无需单独定义传递查询条件的类//缺点:当向Map中存放参数时,key必须与动态sql保持一致()//public List<Member> searchMember(HashMap<String,Object> params);// 也可以定义专门用于存放查询条件的实体类存放参数//优点:设置参数时无需关注属性名//缺点:需要单独定义一个类来封装参数public List<Member> searchMember(MemberSearchCondition params);
}

12.3 if

<resultMap id="memberMap" type="Member"><id column="member_id" property="memberId"/><result column="member_nick" property="memberNick"/><result column="member_gender" property="memberGender"/><result column="member_age" property="memberAge"/><result column="member_city" property="memberCity"/>
</resultMap><select id="searchMember" resultMap="memberMap">select member_id,member_nick,member_gender,member_age,member_cityfrom memberswhere 1=1<if test="gender != null">  <!--gender 就是参数对象的属性/参数Map的key-->and member_gender=#{gender}</if><if test="minAge != null">and member_age &gt;= #{minAge}   <!-- &gt; --></if><if test="maxAge != null">and member_age &lt;= #{maxAge}  <!-- &lt; --></if><if test="city != null">and member_city = #{city}</if>
</select>

测试

 @Test
public void testSearchMember() {HashMap<String,Object> params = new HashMap<String, Object>();params.put("gender","女");params.put("minAge",18);//params.put("maxAge",23);params.put("city","武汉");//-----------------------------------------------------------------------MemberSearchCondition params2 = new MemberSearchCondition();params2.setGender("女");//params2.setMinAge(21);//params2.setMaxAge(30);//params2.setCity("武汉");//==========================================================================MemberDAO memberDAO = MyBatisUtil.getMapper(MemberDAO.class);List<Member> members = memberDAO.searchMember(params2);for (Member m: members) {System.out.println(m);}
}

12.4 where

<select id="searchMember" resultMap="memberMap">select member_id,member_nick,member_gender,member_age,member_cityfrom members<where><if test="gender != null">  <!--gender 就是参数对象的属性/参数Map的key-->and member_gender=#{gender}</if><if test="minAge != null">and member_age &gt;= #{minAge}   <!-- &gt; --></if><if test="maxAge != null">and member_age &lt;= #{maxAge}  <!-- &lt; --></if><if test="city != null">and member_city = #{city}</if></where>order by member_age
</select>

12.5 trim

<select id="searchMember" resultMap="memberMap">select member_id,member_nick,member_gender,member_age,member_cityfrom members<trim prefix="where" prefixOverrides="and | or" suffix="order by member_age"><if test="gender != null">  <!--gender 就是参数对象的属性/参数Map的key-->and member_gender=#{gender}</if><if test="minAge != null">and member_age &gt;= #{minAge}   <!-- &gt; --></if><if test="maxAge != null">and member_age &lt;= #{maxAge}  <!-- &lt; --></if><if test="city != null">and member_city = #{city}</if></trim>
</select>

12.6 foreach

public interface MemberDAO {//查询指定城市的会员public List<Member> searchMemberByCity(List<String> cities);
}
<select id="searchMemberByCity" resultMap="memberMap">select member_id,member_nick,member_gender,member_age,member_cityfrom members where member_city in<foreach collection="list" item="cityName" separator="," open="(" close=")">#{cityName}</foreach>
</select>

测试

 @Test
public void searchMemberByCity() {List<String> cities = new ArrayList<String>();cities.add("厦门");cities.add("宜昌");MemberDAO memberDAO = MyBatisUtil.getMapper(MemberDAO.class);List<Member> members = memberDAO.searchMemberByCity(cities);for (Member m: members) {System.out.println(m);}
}

十三、模糊查询

案例:根据昵称查询会员信息(模糊匹配 like)

13.1 模糊查询实现

13.1.1 DAO
public interface MemberDAO {//根据昵称查询用户信息——模糊查询// 模糊查询需要使用${}取值,与sql进行拼接// 在使用${}时,即使只有一个参数也需要使用@Param注解声明参数的key(非String对象参数可以不用声明)public List<Member> searchMemberByNick(@Param("keyWord") String keyWord);}
13.1.2 映射文件
<!--如果参数时String类型,需要parameterType声明参数类型-->
<select id="searchMemberByNick" parameterType="java.lang.String" resultMap="memberMap">select member_id,member_nick,member_gender,member_age,member_cityfrom memberswhere member_nick like '%${keyWord}%'
</select>
13.1.3 测试
@Test
public void testSearchMemberByNick(){MemberDAO memberDAO = MyBatisUtil.getMapper(MemberDAO.class);List<Member> members = memberDAO.searchMemberByNick("花");for (Member m: members) {System.out.println(m);}
}

13.2 #{}和${}的区别

  • ${key} 表示获取参数,先获取参数的值拼接到SQL语句中,再编译执行SQL语句;可能引起SQL注入问题
  • #{key} 表示获取参数,先完成SQL编译(预编译),预编译之后再将获取的参数设置到SQL与中 ,可以避免SQL注入问题

十四、MyBatis日志配置

MyBatis做为一个封装好的ORM框架,其运行过程我们没办法跟踪,为了让开发者了解MyBatis执行流程及每个执行步骤所完成的工作,MyBatis框架本身支持log4j日志框架,对运行的过程进行跟踪记录。我们只需对MyBatis进行相关的日志配置,就可以看到MyBatis运行过程中的日志信息。

14.1 添加日志框架依赖

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>

14.2 添加日志配置文件

  • 在resources目录下创建名为 log4j.properties文件
  • log4j.properties文件配置日志输出的方式
# 声明日志的输出级别及输出方式
log4j.rootLogger=DEBUG,stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 定义日志的打印格式  %t 表示线程名称  %5p 日志级别 %msg日志信息
log4j.appender.stdout.layout.ConversionPattern=[%t] %5p - %msg \:%m%n

14.3 日志信息的级别

在使用日志框架输出日志信息的时候,会根据输出的日志信息的重要程度分为5个级别

级别说明
DEBUG输出调试信息
INFO输出提示信息
WARN输出警告信息
ERROR一般性错误信息
FATAL致命性错误信息

十五、配置数据库连接池-整合Druid

MyBatis做为一个ORM框架,在进行数据库操作时是需要和数据库连接连接的,MyBatis支持基于数据库连接池的连接创建方式。

当我们配置MyBatis数据源时,只要配置了dataSource标签的type属性值为POOLED时,就可以使用MyBatis内置的连接池管理连接。

如果我们想要使用第三方的数据库连接池,则需进行自定义配置。

15.1 常见的连接池

  • DBCP
  • C3P0
  • Druid 性能也比较好,提供了比较便捷的监控系统
  • Hikari 性能最好
功能dbcpdruidc3p0HikariCP
是否支持PSCache
监控jmxjmx/log/httpjmx,logjmx
扩展性
sql拦截及解析支持
代码简单中等复杂简单
更新时间2015.8.62015.10.102015.12.092015.12.3
特点依赖于common-pool阿里开源,功能全面历史久远,代码逻辑复杂,且不易维护优化力度大,功能简单,起源于boneCP
连接池管理LinkedBlockingDeque数组threadlocal+CopyOnWriteArrayList

15.2 添加Druid依赖

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.5</version>
</dependency>

15.3 创建Druid连接池工厂

public class DruidDataSourceFactory extends PooledDataSourceFactory {public DruidDataSourceFactory() {this.dataSource = new DruidDataSource();}
}

15.4 将DruidDataSourceFactory配置给MyBatis数据源

<environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"></transactionManager><!--   POOLED 使用MyBatis内置的连接池实现   --><!--  mybatis需要一个连接池工厂,这个工厂可以产生数据库连接池  PooledDataSourceFactory --><dataSource type="com.qfedu.utils.DruidDataSourceFactory"><property name="driverClass" value="${driver}"/><property name="jdbcUrl" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment>
</environments>

十六、MyBatis缓存

MyBatis是基于JDBC的封装,使数据库操作更加便捷;MyBatis除了对JDBC操作步骤进行封装之外也对其性能进行了优化:

  • 在MyBatis引入缓存机制,用于提升MyBatis的检索效率
  • 在MyBatis引入延迟加载机制,用于减少对数据库不必要的访问

16.1 缓存的工作原理

缓存,就是存储数据的内存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ANrr7onU-1639493777655)(imgs/1616654926110.png)]

16.2 MyBatis缓存

MyBatis缓存分为一级缓存和二级缓存

16.2.1 一级缓存

一级缓存也叫做SqlSession级缓存,为每个SqlSession单独分配的缓存内存,无需手动开启可直接使用;多个SqlSession的缓存是不共享的。

特性:

1.如果多次查询使用的是同一个SqlSession对象,则第一次查询之后数据会存放到缓存,后续的查询则直接访问缓存中存储的数据;

2.如果第一次查询完成之后,对查询出的对象进行修改(此修改会影响到缓存),第二次查询会直接访问缓存,造成第二次查询的结果与数据库不一致;

3.当我们进行在查询时想要跳过缓存直接查询数据库,则可以通过sqlSession.clearCache();来清除当前SqlSession的缓存;

4.如果第一次查询之后第二查询之前,使用当前的sqlsession执行了修改操作,此修改操作会使第一次查询并缓存的数据失效,因此第二次查询会再次访问数据库。

测试代码:

@Test
public void testQueryMemberById(){SqlSession sqlSession1 = MyBatisUtil.getSqlSessionFactory().openSession();SqlSession sqlSession2 = MyBatisUtil.getSqlSessionFactory().openSession();MemberDAO memberDAO1 = sqlSession1.getMapper(MemberDAO.class);Member member1 = memberDAO1.queryMemberById(1);System.out.println(member1);member1.setMemberAge(99);sqlSession1.clearCache();System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");MemberDAO memberDAO2 = sqlSession1.getMapper(MemberDAO.class);Member member2 =memberDAO2.queryMemberById(1);System.out.println(member2);
}
16.2.2 两次查询与数据库数据不一致问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D5lZ6Fzq-1639493777655)(imgs/1616660132980.png)]

16.2.3 二级缓存

二级缓存也称为SqlSessionFactory级缓存,通过同一个factory对象获取的Sqlsession可以共享二级缓存;在应用服务器中SqlSessionFactory是单例的,因此我们二级缓存可以实现全局共享。

特性:

1.二级缓存默认没有开启,需要在mybatis-config.xml中的settings标签开启

2.二级缓存只能缓存实现序列化接口的对象

  • 在mybatis-config.xml开启使用二级缓存
<settings><setting name="cacheEnabled" value="true"/>
</settings>
  • 在需要使用二级缓存的Mapper文件中配置cache标签使用功能二级缓存
<cache/>
  • 被缓存的实体类实现序列化接口
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Member implements Serializable {private int memberId;private String memberNick;private String memberGender;private int memberAge;private String memberCity;
}
  • 测试
@Test
public void testQueryMemberById(){SqlSessionFactory factory =MyBatisUtil.getSqlSessionFactory();// 1.多个SqlSession对象必须来自于同一个SqlSessionFactorySqlSession sqlSession1 = factory.openSession(true);SqlSession sqlSession2 = factory.openSession(true);System.out.println(sqlSession1 == sqlSession2);MemberDAO memberDAO1 = sqlSession1.getMapper(MemberDAO.class);Member member1 = memberDAO1.queryMemberById(1);System.out.println(member1);sqlSession1.commit();  //2.第一次查询之后执行sqlSession1.commit(),会将当前sqlsession的查询结果缓存到二级缓存System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");MemberDAO memberDAO2 = sqlSession2.getMapper(MemberDAO.class);Member member2 =memberDAO2.queryMemberById(1);System.out.println(member2);
}

16.3 查询操作的缓存开关

<select id="queryMemberById" resultMap="memberMap" useCache="false">select member_id,member_nick,member_gender,member_age,member_cityfrom memberswhere member_id=#{mid}
</select>

十七、延迟加载

延迟加载——如果在MyBatis开启了延迟加载,在执行了子查询(至少查询两次及以上)时,默认只执行第一次查询,当用到子查询的查询结果时,才会触发子查询的执行;如果无需使用子查询结果,则子查询不会执行.

开启延迟加载:

<resultMap id="classMap" type="Clazz"><id column="cid" property="classId"/><result column="cname" property="className"/><result column="cdesc" property="classDesc"/><collection property="stus" select="com.qfedu.dao.StudentDAO.queryStudentsByCid" column="cid" fetchType="lazy"/>
</resultMap><select id="queryClassByCid" resultMap="classMap">select cid,cname,cdescfrom classeswhere cid=#{cid}
</select>

测试代码:

@Test
public void queryClassByCid() {ClassDAO classDAO = MyBatisUtil.getMapper(ClassDAO.class);Clazz clazz = classDAO.queryClassByCid(1);System.out.println(clazz.getClassName());System.out.println("-----------------------------------");System.out.println(clazz.getStus());
}

运行日志:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2B6mC1Gv-1639493777656)(imgs/1616663783657.png)]

练习任务

jsp+servlet+mybatis

商品信息的CRUD

  • 添加商品
  • 商品列表+分页
  • 删除商品
  • 修改商品
  • 商品详情

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450439.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android studio : clang++.exe: error: invalid linker name in argument '-fuse-ld=bfd

公司jenkins上的C编译器最近换成了clang&#xff0c;今天更新了代码发现本地的C/C代码用NDK编译不过了&#xff0c;提示&#xff1a; “clang.exe: error: invalid linker name in argument -fuse-ldbfd” 解决办法&#xff1a; 将Android.mk文件中的“LOCAL_LDFLAGS -fuse-ld…

Git知识点

一、Git简介 1.1 项目的版本管理 在项目开发过程中&#xff0c;项目没开发到一个节点就会对当前项目进行备份&#xff0c;这个备份就是项目的一个版本&#xff1b;当我们继续开发一个阶段后&#xff0c;再次进行备份&#xff0c;就生成新的版本——多个版本的集合就是项目的版…

(1)初始化项目

2019独角兽企业重金招聘Python工程师标准>>> &#xff08;1&#xff09;初始化项目 1 使用vue-cli初始化项目 vue init webpack my-renren得到以下输出&#xff1a; ? Project name my-renren ? Project description A Vue.js project ? Author neumeng <4048…

C语言变量

C语言二进制、八进制、十六进制详解 什么是二制制? 在数学计算中&#xff0c;二进制计数系统的公分母是最小的&#xff0c;它以2为基数。你还记得在小学或中学时所学的不同的计数系统吗?笔者在上小学时&#xff0c;曾在一堂数学课中学过以6为基数的计数系统&#xff1b;你先…

Spring Data JPA - 参考文档 地址

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Spring Data JPA - 参考文档 文档地址

JS内置方法(Array)

concat() 用于连接两个或多个数组&#xff0c;该方法不会改变现有的数组&#xff0c;而是返回被连接数组的一个副本。join() 把数组中的所有元素放入一个字符串&#xff0c;元素是通过指定的分隔符进行分隔的。若省略了分隔符参数&#xff0c;则使用逗号作为分隔符。push() 向…

模切ERP和免费OA系统是互相结合提高效率

模切ERP和免费OA系统是互相结合提高效率在模切行业中&#xff0c;模切ERP在管理上的作用占了很大的比重&#xff0c;但是免费OA在管理上的地位都不容忽视的。点晴OA的核心问题是如何提高日常的办公效率问题。因此点晴OA系统里包含的功能是非常全面&#xff0c;如&#xff1a;办…

maven知识点

一、Maven简介 1.1 在项目中如何导入jar包&#xff1f; 下载jar包 &#xff08;mvn&#xff09;将下载的jar包拷贝到项目中&#xff08;WEB-INF/lib&#xff09;选择jar文件–右键–Add as Library 1.2 传统导入jar包的方式存在什么问题&#xff1f; 步骤多&#xff08;相对…

使用SpringBoot yml配置文件

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.上一次我们已经使用SpringBoot实现了一个简单的HelloWord程序&#xff0c;辣么接下来我们简单的使用一下他的yml格式的配置文件。 2.在…

软件行业资讯

为什么只有设计师才能发明流行的新语言 先回顾一下知名编程语言的作者和创造时间&#xff1a;Fortran 语言&#xff0c;50年代&#xff0c;IBM 研究员&#xff1b;Lisp 语言&#xff0c;50年代&#xff0c;MIT 的教授和学生&#xff1b;C语言&#xff0c;70年代&#xff0c;贝尔…

spring知识点

一、Spring概述 1.1 web项目开发中的耦合度问题 在Servlet中需要调用service中的方法&#xff0c;则需要在Servlet类中通过new关键字创建Service的实例 public interface ProductService{public List<Product> listProducts(); }public class ProductServiceImpl1 imple…

Linux系统下的权限试题测试

不会做的留言&#xff0c;到时在发布答案&#xff01;一、 有两个参赛团队team1、team2&#xff0c;两个团队各3人, 这两个团队互相竞争&#xff0c;各需提交一份报告&#xff0c;每组成员可以修改自己团队内的所有文件&#xff0c;且不能让其他团队的人修改自己的文件内容&…

电子科大软件系统架构设计——软件建模详细设计

文章目录 软件建模详细设计概述软件建模详细设计目标软件建模详细设计原则开闭原则里氏 (Liskov) 替换原则依赖倒置原则接口分离原则单一职责原则最少知识原则&#xff08;迪米特法则&#xff09;高内聚原则松耦合原则可重用原则 软件建模详细设计内容 UML 软件静态结构视图建模…

YAML文件解析

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 YAML是“另一种标记语言”的外语缩写,YAML 是一种比JSON&#xff08;json多层次{ 与 [ 会被搞晕的&#xff09;更直观的表现形式&#xf…

120分钟React快速扫盲教程

在教程开端先说些题外话&#xff0c;我喜欢在学习一门新技术或读过一本书后&#xff0c;写一篇教程或总结&#xff0c;既能帮助消化&#xff0c;也能加深印象和发现自己未注意的细节&#xff0c;写的过程其实仍然是一个学习的过程。有个记录的话&#xff0c;在未来需要用到相关…

springmvc知识点

一、SpringMVC概述 Spring MVC 是由Spring官方提供的基于MVC设计理念的web框架。 SpringMVC是基于Servlet封装的用于实现MVC控制的框架&#xff0c;实现前端和服务端的交互。 1.1 SpringMVC优势 严格遵守了MVC分层思想 采用了松耦合、插件式结构&#xff1b;相比较于我们封装的…

spring @component的作用

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1、controller 控制器&#xff08;注入服务&#xff09; 2、service 服务&#xff08;注入dao&#xff09; 3、repository dao&#xff…

微信小程序 悬浮按钮

2019独角兽企业重金招聘Python工程师标准>>> 效果视频 https://pan.baidu.com/s/1yfrDaG9YAX0--v0EA3awZA 布局需要按照圆形排列&#xff0c;所以我们需要计算每个点的坐标 代码部分 <view styleposition:fixed; wx:for"{{list}}" wx:for-index"i…

C语言const关键字—也许该被替换为readolny

const 是constant 的缩写&#xff0c;是恒定不变的意思&#xff0c;也翻译为常量、常数等。很不幸&#xff0c;正是因为这一点&#xff0c;很多人都认为被const 修饰的值是常量。这是不精确的&#xff0c;精确的说应该是只读的变量&#xff0c;其值在编译时不能被使用&#xff…

dbus服务自启动方法

Linux 一般发行版上 "/usr/share/dbus-1/services/"目录就是dbus放service文件的地方。 需要自动启动的服务器 就在这个目录放一个 service文件&#xff0c;内容如下&#xff1a; $ cat /usr/share/dbus-1/services/dhcdbd.service [D-BUS Service] Namecom.redhat.…