SSM框架学习——MyBatis关联映射

MyBatis关联映射

为什么要关联映射

实际开发中,对数据库操作常常会涉及多张表,所以在OOP中就涉及对象与对象的关联关系。针对多表操作,MyBatis提供关联映射。

关联关系概述

  • 一对一:A类中定义B类的属性b,B类中定义A类属性a。
  • 一对多:一个A类类型对应多个B类。
  • 多对多:在A类中定义B的集合,B中定义A的集合。

嵌套查询与嵌套结果

嵌套查询是通过执行另外一条SQL映射语句来返回预期复杂类型:

  • 嵌套查询是在查询SQL嵌套一个子查询
  • 嵌套查询会执行多条SQL语句
  • 嵌套查询SQL语句编写相对简单

嵌套结果是使用嵌套结果映射来处理的联合结果子集:

  • 嵌套结果是一个嵌套的多表查询SQL
  • 嵌套结果只会执行一条复杂的SQL语句
  • 嵌套结果SQL语句写起来相对麻烦

对于嵌套查询有一个问题,那就是执行多条SQL语句导致性能开销很大。于是就有了MyBatis的延迟加载——fetchType。

实践

创建表

我们还是用之前的账户连接数据库,终端命令可以如下

mysql -u db_mybatis -p

输入密码敲击回车,然后切换数据库到db_mybatis

Windows用户可以用终端或者sqlyog执行下面语句

如果你没有这个数据库请回到前面的章节创建它。

USE db_mybatis;

我们要使用一个新的customer表,所以把之前项目留下的删除掉

DROP TABLE IF EXISTS customer;

重新创建它

CREATE TABLE customer(
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `jobs` varchar(50) DEFAULT NULL,
  `phone` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

给这张表插入两条数据方便我们接下来写代码用

INSERT  INTO customer(`id`,`username`,`jobs`,`phone`) VALUES (1,'zhangsan','teacher','11111111111'),(2,'lisi','student','11111111112');

创建一张idcard表,并设置主键(主码)为id

如果之前存在请删除

DROP TABLE IF EXISTS `idcard`;
CREATE TABLE idcard(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

同样插入两条数据(身份证号是我瞎编的,为了防止巧合不一定符合真实格式,但长度与现实一样)

INSERT  INTO idcard(`id`,`code`) VALUES(1,'37010219800X051118'),(2,'370203199X09092222');

创建persion表,并插入数据

DROP TABLE IF EXISTS person;

CREATE TABLE person(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `card_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_person` (`card_id`),
  CONSTRAINT `FK_person` FOREIGN KEY (`card_id`) REFERENCES `idcard` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT INTO person(`id`,`name`,`age`,`card_id`) values (1,'张三',18,1),(2,'李四',18,2);

创建product表并插入数据

DROP TABLE IF EXISTS product;

CREATE TABLE product(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `price` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT INTO product(`id`,`name`,`price`) values (1,'笔记本电脑',8888.8),(2,'华为手机',6666.6);

创建user表并插入数据

DROP TABLE IF EXISTS user;

CREATE TABLE user(
  `id` int(11) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO user(`id`,`name`,`password`) values (1,'zhangsan','654321'),(2,'lisi','123456');

创建orders

DROP TABLE IF EXISTS orders;
CREATE TABLE orders(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `number` varchar(32) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_orders` (`user_id`),
  CONSTRAINT `FK_orders` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `orders`(`id`,`number`,`user_id`) VALUES (1,'201901',1);

创建orderitem表,还是一样,如果之前存在先删除。这个表一定放后面,否则创建外键会报错。

DROP TABLE IF EXISTS orderitem;

CREATE TABLE orderitem(
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orders_id` int(11) DEFAULT NULL,
  `product_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_orderitem` (`orders_id`),
  KEY `FK_orderitem_product` (`product_id`),
  CONSTRAINT `FK_orderitem_product` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`),
  CONSTRAINT `FK_orderitem` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT INTO orderitem(`id`,`orders_id`,`product_id`) VALUES (1,1,1),(2,1,2);

构建项目

我们新创建一个Maven项目top.cairbin.test5

pom.xml添加依赖包

<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>top.cairbin</groupId>
  <artifactId>test5</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>test5</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    
    <dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
	<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.4</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.33</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
		<dependency>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-core</artifactId>
			<version>1.4.0</version>
		</dependency>
    
    	<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
    
  </dependencies>
</project>

创建与src平级的resources目录,并右键->Build Path->Use as Source Folder

在里面添加一个数据库配置文件db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis
jdbc.username=db_mybatis
jdbc.password=db_mybatis

配置MyBatis,在同目录下创建mybatis-config.xml,这个文件会使用db.properties里面的配置,以${...}的方式调用,在<properties resource="db.properties" />里声明位置。

<?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>
	<properties resource="db.properties" />
	<settings>
		<!-- 延迟加载的开关 -->
		<setting name="lazyLoadingEnabled" value="false" />
		<!-- 设置积极加载(true)或按需加载(false) -->
		<setting name="aggressiveLazyLoading" value="true" />
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<setting name="logImpl" value="STDOUT_LOGGING" />
	</settings>
	<typeAliases>
		<package name="top.cairbin.test5" />
	</typeAliases>
	<!--1.配置环境 ,默认的环境id为mysql -->
	<environments default="mysql">
		<!--1.2.配置id为mysql的数据库环境 -->
		<environment id="mysql">
			<!-- 使用JDBC的事务管理 -->
			<transactionManager type="JDBC" />
			<!--数据库连接池 -->
			<dataSource type="POOLED">
				<!-- 数据库驱动 -->
				<property name="driver" value="${jdbc.driver}" />
				<!-- 连接数据库的url -->
				<property name="url" value="${jdbc.url}" />
				<!-- 连接数据库的用户名 -->
				<property name="username" value="${jdbc.username}" />
				<!-- 连接数据库的密码 -->
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<!--2.配置Mapper的位置 -->
	<mappers>
		<mapper resource="top/cairbin/test5/mapper/CustomerMapper.xml" />
		<mapper resource="top/cairbin/test5/mapper/UserMapper.xml" />
		<mapper resource="top/cairbin/test5/mapper/IdCardMapper.xml" />
		<mapper resource="top/cairbin/test5/mapper/OrdersMapper.xml" />
		<mapper resource="top/cairbin/test5/mapper/PersonMapper.xml" />
		<mapper resource="top/cairbin/test5/mapper/ProductMapper.xml" />
	</mappers>
</configuration>

注意上方的<mapper>的目录,我们一会介绍。

然后添加log4j的配置文件log4j.properties

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.top.cairbin.test5=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

Dao层

我们先把对应的类创建了再说,到src/main/javatop.cairbin.test5创建一个子包,名称为top.cairbin.test5.dao

在我们新创建的包下面编写若干个类

首先是Person类,此时我们的IdCard还没创建,IDE提示错误很正常

package top.cairbin.test5.dao;

public class Person {
	private Integer id;
	private String name;
	private Integer age;
	private Integer cardId;
	private IdCard card;

	public void setId(Integer id) {
		this.id = id;
	}
	
	public Integer getId() {
		return this.id;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return this.name;
	}
	
	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Integer getAge() {
		return this.age;
	}
	
	public Integer getCardId() {
        return cardId;
    }

    public void setCardId(Integer cardId) {
        this.cardId = cardId;
    }
	
	public void setCard(IdCard card) {
		this.card = card;
	}
	
	public IdCard getCard() {
		return this.card;
	}	
}

接下来创建IdCard

package top.cairbin.test5.dao;

public class IdCard {
    private Integer id;
    private String code;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code == null ? null : code.trim();
    }
}

然后是Customer

package top.cairbin.test5.dao;

public class Customer {
    private Integer id;
    private String username;
    private String jobs;
    private String phone;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username == null ? null : username.trim();
    }

    public String getJobs() {
        return jobs;
    }

    public void setJobs(String jobs) {
        this.jobs = jobs == null ? null : jobs.trim();
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone == null ? null : phone.trim();
    }
}

接着是Orders

package top.cairbin.test5.dao;

package top.cairbin.test5.dao;

import java.util.List;

public class Orders {
    private Integer id;
    private String number;
    private Integer userId;
    
    private List<Product> productList;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number == null ? null : number.trim();
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    
    public void setProductList(List<Product> productList) {
    	this.productList = productList;
    }

    public List<Product> getProductList(){
    	return this.productList;
    }   
}

Product

package top.cairbin.test5.dao;

public class Product {
    private Integer id;
    private String name;
    private Double price;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

User

package top.cairbin.test5.dao;

import java.util.List;

public class User {
    private Integer id;
    private String name;
    private String password;

    private List<Orders> ordersList;
    
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }
    
    public void setOrdersList(List<Orders> ordersList) {
    	this.ordersList = ordersList;
    }
    
    public List<Orders> getOrdersList(){
    	return this.ordersList;
    }   
}

Util层

这一层我们来放置一些工具类。创建包top.cairbin.test5.util

然后在下面创建MyBatisHelper

package top.cairbin.test5.util;

import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisHelper {
	private static SqlSessionFactory sqlSessionFactory = null;
	// 初始化SqlSessionFactory对象
	static {
		try {
			// 使用MyBatis提供的Resources类加载MyBatis的配置文件
			Reader reader = 
					Resources.getResourceAsReader("mybatis-config.xml");
			// 构建SqlSessionFactory工厂
			sqlSessionFactory = 
					new SqlSessionFactoryBuilder().build(reader);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	// 获取SqlSession对象的静态方法
	public static SqlSession getSession() {
		return sqlSessionFactory.openSession();
	}
}

Mapper层

接下来我们再为top.cairbin.test5创建一个子包top.cairbin.test5.mapper,该层主要实现数据持久化。

与上面不一样的是,我们这里定义的是接口

首先是CustomerMapper接口

package top.cairbin.test5.mapper;

import top.cairbin.test5.dao.Customer;

public interface CustomerMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Customer record);

    int insertSelective(Customer record);

    Customer selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Customer record);

    int updateByPrimaryKey(Customer record);
}

到这里你可能会问,谁去实现它们呢,还记得mybatis-config.xml里那些<mapper>吗,它们每一个都指定resource到Mapper层,也就是说我们要在这里写XML文件让MyBatis实现这些方法。

第一个是CustomerMapper.xml,注意此处的namespace<resultMap>id,下文同理。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.cairbin.test5.mapper.CustomerMapper">
  <resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Customer">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="jobs" jdbcType="VARCHAR" property="jobs" />
    <result column="phone" jdbcType="VARCHAR" property="phone" />
  </resultMap>
  <sql id="Base_Column_List">
    id, username, jobs, phone
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from customer
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from customer
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="top.cairbin.test5.dao.Customer">
    insert into customer (id, username, jobs, 
      phone)
    values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{jobs,jdbcType=VARCHAR}, 
      #{phone,jdbcType=VARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="top.cairbin.test5.dao.Customer">
    insert into customer
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="username != null">
        username,
      </if>
      <if test="jobs != null">
        jobs,
      </if>
      <if test="phone != null">
        phone,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="username != null">
        #{username,jdbcType=VARCHAR},
      </if>
      <if test="jobs != null">
        #{jobs,jdbcType=VARCHAR},
      </if>
      <if test="phone != null">
        #{phone,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Customer">
    update customer
    <set>
      <if test="username != null">
        username = #{username,jdbcType=VARCHAR},
      </if>
      <if test="jobs != null">
        jobs = #{jobs,jdbcType=VARCHAR},
      </if>
      <if test="phone != null">
        phone = #{phone,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Customer">
    update customer
    set username = #{username,jdbcType=VARCHAR},
      jobs = #{jobs,jdbcType=VARCHAR},
      phone = #{phone,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

对了,请检查你XML中的方法的parameterType属性以及resultType对应类型的包是否正确!!!

然后是IdCardMapper接口

package top.cairbin.test5.mapper;

import top.cairbin.test5.dao.IdCard;

public interface IdCardMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(IdCard record);

    int insertSelective(IdCard record);

    IdCard selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(IdCard record);

    int updateByPrimaryKey(IdCard record);
}

同样在IdCardMapper.xml里实现这些方法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.cairbin.test5.mapper.IdCardMapper">
  <resultMap id="BaseResultMap" type="top.cairbin.test5.dao.IdCard">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="code" jdbcType="VARCHAR" property="code" />
  </resultMap>
  <sql id="Base_Column_List">
    id, code
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from idcard
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from idcard
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="top.cairbin.test5.dao.IdCard">
    insert into idcard (id, code)
    values (#{id,jdbcType=INTEGER}, #{code,jdbcType=VARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="top.cairbin.test5.dao.IdCard">
    insert into idcard
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="code != null">
        code,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="code != null">
        #{code,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.IdCard">
    update idcard
    <set>
      <if test="code != null">
        code = #{code,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.IdCard">
    update idcard
    set code = #{code,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

然后是ProductMapper接口以及ProductMapper.xml

package top.cairbin.test5.mapper;
import top.cairbin.test5.dao.Product;

public interface ProductMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Product record);

    int insertSelective(Product record);

    Product selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Product record);

    int updateByPrimaryKey(Product record);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.cairbin.test5.mapper.ProductMapper">
  <resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Product">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="price" jdbcType="DOUBLE" property="price" />
  </resultMap>
  <sql id="Base_Column_List">
    id, name, price
  </sql>
  
  <select id="findProductByOrderId" parameterType="Integer"   resultType="Product">
		SELECT * from product where id IN(
		   SELECT product_id FROM orderitem  WHERE orders_id = #{id}
		)
	</select>

  
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from product
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from product
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="top.cairbin.test5.dao.Product">
    insert into product (id, name, price
      )
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{price,jdbcType=DOUBLE}
      )
  </insert>
  <insert id="insertSelective" parameterType="top.cairbin.test5.dao.Product">
    insert into product
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="price != null">
        price,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="price != null">
        #{price,jdbcType=DOUBLE},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Product">
    update product
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="price != null">
        price = #{price,jdbcType=DOUBLE},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Product">
    update product
    set name = #{name,jdbcType=VARCHAR},
      price = #{price,jdbcType=DOUBLE}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

对于剩下来的几个Dao层类对应的Mapper需要特别注意下,因为它们的类里都包含复合类型,这也是我们这一章节真正要学习的东西——关联映射。

PersonMapper接口

package top.cairbin.test5.mapper;

import top.cairbin.test5.dao.Person;

public interface PersonMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Person record);

    int insertSelective(Person record);

    Person selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Person record);

    int updateByPrimaryKey(Person record);
}

PersonMapper.xml文件,请重点关注findPersonByIdfindPersonById2这两个地方。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.cairbin.test5.mapper.PersonMapper">

	<resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Person">
    	<id column="id" jdbcType="INTEGER" property="id" />
    	<result column="name" jdbcType="VARCHAR" property="name" />
    	<result column="age" jdbcType="INTEGER" property="age" />
    	<result column="card_id" jdbcType="INTEGER" property="cardId" />
  </resultMap>
  <sql id="Base_Column_List">
    id, name, age, card_id
  </sql>
  
  <!-- 嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
	<select id="findPersonById" parameterType="Integer" 
    resultMap="IdCardWithPersonResult">
		SELECT * from person where id=#{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult">
		<id property="id" column="id" />
		<result property="name" column="name" />
		<result property="age" column="age" />
		<!-- 一对一:association使用select属性引入另外一条SQL语句 -->
		<association property="card" column="card_id" javaType="top.cairbin.test5.dao.IdCard"
			select="top.cairbin.test5.mapper.IdCardMapper.selectByPrimaryKey" />
	</resultMap>

  
  	<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 -->
  	<select id="findPersonById2" parameterType="Integer" 
	                                   resultMap="IdCardWithPersonResult2">
	    SELECT p.*,idcard.code
	    from person p,idcard idcard
	    where p.card_id=idcard.id 
	    and p.id= #{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult2">
	    <id property="id" column="id" />
	    <result property="name" column="name" />
	    <result property="age" column="age" />
	    <association property="card" javaType="IdCard">
	        <id property="id" column="id" />
	        <result property="code" column="code" />
	    </association>
	</resultMap>

  
  
  
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from person
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from person
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="top.cairbin.test5.dao.Person">
    insert into person (id, name, age, 
      card_id)
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}, 
      #{cardId,jdbcType=INTEGER})
  </insert>
  <insert id="insertSelective" parameterType="top.cairbin.test5.dao.Person">
    insert into person
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="age != null">
        age,
      </if>
      <if test="cardId != null">
        card_id,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        #{age,jdbcType=INTEGER},
      </if>
      <if test="cardId != null">
        #{cardId,jdbcType=INTEGER},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Person">
    update person
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        age = #{age,jdbcType=INTEGER},
      </if>
      <if test="cardId != null">
        card_id = #{cardId,jdbcType=INTEGER},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Person">
    update person
    set name = #{name,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      card_id = #{cardId,jdbcType=INTEGER}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

对于上面这么长的文件,最重要的地方是这里

<!-- 一对一:association使用select属性引入另外一条SQL语句 -->
<association property="card" column="card_id"   javaType="top.cairbin.test5.dao.IdCard"
select="top.cairbin.test5.mapper.IdCardMapper.selectByPrimaryKey" />

为了看到效果,我们在mybatis-config.xml里将延迟加载关掉。

<settings>
	<!-- 延迟加载的开关 -->
	<!-- 为了让大家看到关联关系的效果,我们在这里关闭了延迟加载 -->  
	<setting name="lazyLoadingEnabled" value="false" />  
	<setting name="aggressiveLazyLoading" value="true"/>  
</settings>

创建UserMapper接口和UserMapper.xml

package top.cairbin.test5.mapper;

import top.cairbin.test5.dao.User;

public interface UserMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.cairbin.test5.mapper.UserMapper">
  <resultMap id="BaseResultMap" type="top.cairbin.test5.dao.User">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="password" jdbcType="VARCHAR" property="password" />
    
    <collection property="ordersList" column="id" ofType="Orders" 
		     select="top.cairbin.test5.mapper.OrdersMapper.findOrdersWithUser">
	</collection>

    
  </resultMap>
  <sql id="Base_Column_List">
    id, name, password
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from user
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from user
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="top.cairbin.test5.dao.User">
    insert into user (id, name, password
      )
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}
      )
  </insert>
  <insert id="insertSelective" parameterType="top.cairbin.test5.dao.User">
    insert into user
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="password != null">
        password,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        #{password,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.User">
    update user
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        password = #{password,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.User">
    update user
    set name = #{name,jdbcType=VARCHAR},
      password = #{password,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

最后OrdersMapperOrdersMapper.xml

package top.cairbin.test5.mapper;

import top.cairbin.test5.dao.Orders;

public interface OrdersMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Orders record);

    int insertSelective(Orders record);

    Orders selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Orders record);

    int updateByPrimaryKey(Orders record);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.cairbin.test5.mapper.OrdersMapper">
  <resultMap id="BaseResultMap" type="top.cairbin.test5.dao.Orders">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="number" jdbcType="VARCHAR" property="number" />
    <result column="user_id" jdbcType="INTEGER" property="userId" />
  </resultMap>
  <sql id="Base_Column_List">
    id, number, user_id
  </sql>
  
  <select id="findOrdersWithUser" parameterType="Integer" 
              resultMap="BaseResultMap">
		select * from orders WHERE user_id=#{id}	
	</select>

  
  
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from orders
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from orders
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="top.cairbin.test5.dao.Orders">
    insert into orders (id, number, user_id
      )
    values (#{id,jdbcType=INTEGER}, #{number,jdbcType=VARCHAR}, #{userId,jdbcType=INTEGER}
      )
  </insert>
  <insert id="insertSelective" parameterType="top.cairbin.test5.dao.Orders">
    insert into orders
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="number != null">
        number,
      </if>
      <if test="userId != null">
        user_id,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="number != null">
        #{number,jdbcType=VARCHAR},
      </if>
      <if test="userId != null">
        #{userId,jdbcType=INTEGER},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.cairbin.test5.dao.Orders">
    update orders
    <set>
      <if test="number != null">
        number = #{number,jdbcType=VARCHAR},
      </if>
      <if test="userId != null">
        user_id = #{userId,jdbcType=INTEGER},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.cairbin.test5.dao.Orders">
    update orders
    set number = #{number,jdbcType=VARCHAR},
      user_id = #{userId,jdbcType=INTEGER}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

我们编写测试类,在src/test/java下的top.cairbin.test5

PersonTest类来测试一对一的关系

package top.cairbin.test5;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import top.cairbin.test5.dao.Person;
import top.cairbin.test5.util.*;

public class PersonTest {
	@Test
    public void findPersonByIdTest() {
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MyBatisHelper.getSession();
        // 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
        Person person = session.selectOne("top.cairbin.test5.mapper." 
                                   + "PersonMapper.selectByPrimaryKey", 1);
        // 3、输出查询结果信息
        System.out.println(person);
        // 4、关闭SqlSession
        session.close();
    }

	//测试一对一(嵌套结果):
	@Test
    public void findPersonByIdTest2() {
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MyBatisHelper.getSession();
        // 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
        Person person = session.selectOne("top.cairbin.test5.mapper." 
                                   + "PersonMapper.findPersonById2", 1);
        // 3、输出查询结果信息
        System.out.println(person);
        // 4、关闭SqlSession
        session.close();
    }
}

点击运行,两个方法所用时间差距不小。

我们再编写测试类UserTest来测试一对多

package top.cairbin.test5;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import top.cairbin.test5.dao.User;
import top.cairbin.test5.util.MyBatisHelper;

public class UserTest {
	@Test
    public void findUserTest() {
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MyBatisHelper.getSession();
        // 2、查询id为1的用户信息,注意包名为mapper层的
        User user = session.selectOne("top.cairbin.test5.mapper."
                                + "UserMapper.selectByPrimaryKey", 1);
        // 3、输出查询结果信息
        System.out.println(user);
        // 4、关闭SqlSession
        session.close();
    }

}

最后编写OrdersTest来测试多对多

package top.cairbin.test5;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import top.cairbin.test5.dao.Orders;
import top.cairbin.test5.util.MyBatisHelper;

public class OrdersTest {
	@Test
    public void findOrdersTest(){
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MyBatisHelper.getSession();
        // 2、查询id为1的订单中的商品信息
        Orders orders = session.selectOne("top.cairbin.test5.mapper."
                               + "OrdersMapper.selectByPrimaryKey", 1);
        // 3、输出查询结果信息
        System.out.println(orders);
        // 4、关闭SqlSession
        session.close();
    }
}

总结

在本章节,我们学习了MyBatis的关联映射。此外,你会发现我们写代码不再像以前一样只放在一个包里,而是创建好几个子包分层放置不同的代码,这有利于代码逻辑清晰并且方便维护,这种分层设计已经有一个正式项目的雏形了,当你写完这些东西的时候项目目录应该与我差不多。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

华为云RDS for Mysql入门与配置

华为云RDS for MySQL支持混合SSD实例&#xff0c;它结合了华为云容器、本地SSD盘和高速云盘。 优势&#xff1a; 主备实例提供故障自动切换和手动切换&#xff0c;业务中断时间为秒级&#xff0c;以及异地灾难备份&#xff0c;最大程度上在出现故障的情况下保障整个数据库集群…

自动驾驶杂谈

在2024年的今天&#xff0c;自动驾驶技术已经迈向了一个崭新的阶段&#xff0c;日趋成熟与先进。昨日&#xff0c;我有幸亲眼目睹了自动驾驶车辆在道路上自如行驶的场景。然而&#xff0c;在市区拥堵的路段中&#xff0c;自动驾驶车辆显得有些力不从心&#xff0c;它们时而疾驰…

贝锐蒲公英企业路由器双机热备,保障异地组网可靠、不中断

对于关键业务&#xff0c;比如&#xff1a;在线支付系统、远程医疗监控系统、重要数据中心等&#xff0c;一旦网络发生故障&#xff0c;可能导致巨大的损失或影响&#xff0c;因此需确保网络拥有极高的可靠性、稳定性和容错能力。 面对此类场景和需求&#xff0c;贝锐蒲公英异…

Linux中间件(nginx搭建、LNMP服务搭建)

目录 一、安装nginx 第一步、下载nginx的压缩包到Linux中 ​第二步、安装依赖 第三步&#xff1a;安装 nginx 第四步&#xff1a;启动nginx 第五步&#xff1a;测试nginx 二、 nginx的配置文件 nginx.conf文件内容解读 案例&#xff1a;发布多个网站 二、lamp/lnmp …

【LeetCode】热题100 刷题笔记

文章目录 T1 两数之和T49 字母异位词分组常用小技巧 T1 两数之和 链接&#xff1a;1. 两数之和 题目&#xff1a; 【刷题感悟】这道题用两层for循环也能做出来&#xff0c;但我们还是要挑战一下时间复杂度小于 O ( n 2 ) O(n^2) O(n2)的解法&#xff0c;不能因为它是第一道 …

AIGC-Stable Diffusion发展及原理总结

目录 一. AIGC介绍 1. 介绍 2. AIGC商业化方向 3. AIGC是技术集合 4. AIGC发展三要素 4.1 数据 4.2 算力 4.3 算法 4.3.1 多模态模型CLIP 4.3.2 图像生成模型 二. Stable Diffusion 稳定扩散模型 1. 介绍 1.1 文生图功能&#xff08;Txt2Img) 1.2 图生图功能&…

每日一题 --- 右旋字符串[卡码][Go]

右旋字符串 题目&#xff1a;55. 右旋字符串&#xff08;第八期模拟笔试&#xff09; (kamacoder.com) 题目描述 字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k&#xff0c;请编写一个函数&#xff0c;将字符串中的后面…

DHCP服务搭建

DHCP搭建 一、DHCP简介 1、概念 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;是一种网络协议&#xff0c;用于自动分配IP地址和其他网络配置信息给网络上的设备。通过DHCP&#xff0c;计算机或其他设备可以自动获取IP地址、…

使用CSS计数器,在目录名称前加上了序号,让目录看起来更加井然有序

目录&#xff08;Text of Contents缩写为TOC&#xff09;&#xff0c;其实就是一篇文章的概要或简述。这好比&#xff0c;去书店买书&#xff0c;先是被这本书的标题所吸引&#xff0c;而后我们才会&#xff0c;翻开这本书目录&#xff0c;看看这本书主要是在讲些什么&#xff…

设置浏览器声音外放,其他声音耳机里放

需求描述&#xff1a; 我想在耳机里听歌&#xff0c;浏览器里的声音外放 找到这个面板 让浏览器的声音输出设为&#xff0c;扬声器

增加网站搜索引擎排名的6个准则

怎样提高网站排名首页 在竞争激烈的网络世界中&#xff0c;网站的排名对于吸引流量和提升曝光至关重要。登上搜索引擎结果页面的首页&#xff0c;意味着更多的曝光和点击率。以下是一些方法&#xff0c;可以帮助您提高网站在搜索引擎中的排名&#xff0c;让其跻身首页&#xf…

golang语言系列:Scrum、Kanban等敏捷管理策略

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 golang语言系列 文章&#xff0c;主要对编程通用技能 Scrum、Kanban等敏捷管理策略 进行学习 1.什么是敏捷开发 敏捷是一个描述软件开发方法的术语&#xff0c;它强调增量交付、团队协作、持续规划和持续学习。…

加密软件VMProtect教程:使用脚本-功能

VMProtect是新一代软件保护实用程序。VMProtect支持德尔菲、Borland C Builder、Visual C/C、Visual Basic&#xff08;本机&#xff09;、Virtual Pascal和XCode编译器。 同时&#xff0c;VMProtect有一个内置的反汇编程序&#xff0c;可以与Windows和Mac OS X可执行文件一起…

【论文阅读】DETR 论文逐段精读

【论文阅读】DETR 论文逐段精读 文章目录 【论文阅读】DETR 论文逐段精读&#x1f4d6;DETR 论文精读【论文精读】&#x1f310;前言&#x1f4cb;摘要&#x1f4da;引言&#x1f9ec;相关工作&#x1f50d;方法&#x1f4a1;目标函数&#x1f4dc;模型结构⚙️代码 &#x1f4…

Navicat工具使用

Navicat的本质&#xff1a; 在创立连接时提前拥有了数据库用户名和密码 双击数据库时&#xff0c;相当于建立了一个链接关系 点击运行时&#xff0c;远程执行命令&#xff0c;就像在xshell上操作Linux服务器一样&#xff0c;将图像化操作转换成SQL语句去后台执行 一、打开Navi…

plasmo内容UI组件层级过高导致页面展示错乱

我使用plasmo写了一个行内样式的UI组件&#xff0c;但是放到页面上之后&#xff0c;会和下拉组件出现层级错乱&#xff0c;看了一下样式&#xff0c;吓我一跳&#xff1a;层级竟然设置的如此之高 所以就需要将层级设置低一点&#xff1a; #plasmo-shadow-container {z-index: …

Java 操作 Hadoop 集群之 HDFS 的应用案例详解

Java 操作 Hadoop 注意:本文内容基于 Hadoop 集群搭建完成基础上: Linux 系统 CentOS7 上搭建 Hadoop HDFS集群详细步骤 本文的内容是基于下面前提: Hadoop 集群搭建完成并能正常启动和访问Idea 和 Maven 分别安装完成需要有 JavaSE 基础和熟悉操作hadoop 的 hdfs dfs 命令…

实验04_OSPF&RIP选路实验

实验拓扑 IP地址规划 拓扑中的 IP 地址段采用&#xff1a;172.16.AB.X/24。其中 AB 为两台路由器编号组合&#xff0c;例如&#xff1a;R3-R6 之间的 AB 为 36&#xff0c;X 为路由器编号&#xff0c;例如R3 的 X3所有路由器都有一个 loopback 0 接口&#xff0c;地址格式为&…

在 Three.js 中,`USDZExporter` 类用于将场景导出为 USDZ 格式,这是一种用于在 iOS 平台上显示增强现实(AR)内容的格式。

demo 案例 在 Three.js 中&#xff0c;USDZExporter 类用于将场景导出为 USDZ 格式&#xff0c;这是一种用于在 iOS 平台上显示增强现实&#xff08;AR&#xff09;内容的格式。下面是关于 USDZExporter 的入参、出参、方法和属性的讲解&#xff1a; 入参 (Parameters): sc…

【Frida】【Android】 07_爬虫之网络通信库HttpURLConnection

&#x1f6eb; 系列文章导航 【Frida】【Android】01_手把手教你环境搭建 https://blog.csdn.net/kinghzking/article/details/136986950【Frida】【Android】02_JAVA层HOOK https://blog.csdn.net/kinghzking/article/details/137008446【Frida】【Android】03_RPC https://bl…