`

mybatis入门实例总结

阅读更多

 

mybatis是一个orm框架,其特点是需要使用原生sql语句,这一点跟hibernate有所不同,hibernate在数据持久化的时候基本上可以不用原生的sql语句(当然也可以使用)。

好吧,这里还是具体来写写怎么使用mybatis吧。

首先,导包问题,mybatis使用需要的jar包还是比较简单的,只需要一个mybatis-版本号.jar包以及对应数据库驱动的jar包,对应jar包查看附件。

其次,主配置文件:

这个配置文件名称可以随意名称的xml文件,当然只需要在获取sqlsessionfactory时对应这个文件名称即可,具体实例如下:

String resource = "conf.xml";
		InputStream is = DBFactory.class.getClassLoader().getResourceAsStream(resource);
		factory = new SqlSessionFactoryBuilder().build(is);

这里我的配置文件的名称就为conf.xml。在这里再补充一点吧,mybatis可以不用通过配置文件来获取sqlsessionfactory对象,可以直接使用java代码获取,这个官方文档上的说明是可以,但是不推荐使用,所以这里暂且先不记录了。

接下来还是来看看conf.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 default="development">
		<environment id="development">
		   <!-- 配置事物 -->
		   <transactionManager type="JDBC" />
	       <!-- 配置数据库连接信息 -->
	       <dataSource type="POOLED">
	         <property name="driver" value="com.mysql.jdbc.Driver" />
	         <property name="url" value="jdbc:mysql://localhost:3306/school" />
	         <property name="username" value="root" />
	         <property name="password" value="a123" />
	       </dataSource>
		</environment>
	</environments>
	
	<mappers>
		<mapper resource="cn/bdx/mapper/userMapper.xml" />
		<mapper resource="cn/bdx/mapper/teacherMapper.xml" />
	</mappers>

</configuration>

 这里只是使用了environments与mappers这两个比较简单基本的标签,

environments表示的是链接的数据库,这里如果需要链接多个数据库,可以写多个environments,

每个SqlSessionFactory 实例只能选择一个运行环境

mappers表示的匹配对应的pojo,这里使用的xml文件方式,所以写法如上,如果是注解方式,其写法如下:

<mappers>
		<mapper class="cn.bdx.dao.intf.UserDao"/>
	</mappers>

 configuration下还有很多其他的子元素,这里就不详细描述了。

接下来基于配置文件方式的使用吧,主配置文件conf.xml文件如上

POJO类:

package cn.bdx.model;

public class User {
	private Integer id;
	private String name;
	private Integer age;
	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;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	
	
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
	
	
}

 对应mapper的配置文件(名称为userMappper.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="cn.bdx.mapper.userMapper">
   		<select id="getUser"  parameterType="int" resultType="cn.bdx.model.User">
   			select * from user_test where id=#{id}
   		</select>
   </mapper>

 具体使用:

@Test
	public void testSelectUser() {
		int id = 1;
		SqlSession session = DBFactory.getSession();
		User user = (User)session.selectOne("cn.bdx.mapper.userMapper.getUser", id);
		System.out.println(user);
	}

说一说这个方法中 session.selectOne("cn.bdx.mapper.userMapper.getUser", id)第一个参数是userMapper.xml文件中<mapper>标签中的namaspace的值与<select>标签中id的值的组合。到这里一个基本使用查询的mybatis的实例就结束了,个人感觉还是比较简单的。

接下来说说注解方式的使用吧。注解方式在前面说过在主配置文件(conf.xml)中需要将<mapper>标签更改一下,更改之后就没有了userMapper.xml文件了,所以到这里应该考虑的是userMapper.xml文件所做的事情我们在哪里完成呢?答案当然是使用注解,但是注解在哪里写呢,需要写一些什么样的注解呢?

好吧,来看看整个基于注解方式的代码是怎么写的吧:

conf.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 default="development">
		<environment id="development">
		   <!-- 配置事物 -->
		   <transactionManager type="JDBC" />
	       <!-- 配置数据库连接信息 -->
	       <dataSource type="POOLED">
	         <property name="driver" value="com.mysql.jdbc.Driver" />
	         <property name="url" value="jdbc:mysql://localhost:3306/hibernate" />
	         <property name="username" value="root" />
	         <property name="password" value="123456" />
	       </dataSource>
		</environment>
	</environments>
	
	<mappers>
		<mapper class="cn.bdx.dao.intf.UserDao"/>
	</mappers>
</configuration>

 User类:

package cn.bdx.model;

public class User {

	private int id;
	private String name;
	private int age;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
	
	
}

 UserDao类:

package cn.bdx.dao.intf;

import java.util.List;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;

import cn.bdx.model.User;

public interface UserDao {
	@Insert("insert into t_user (name,age) values(#{name},#{age})")
	public int addUser(User user);
	
	
	@Select("select * from t_user")
	public List<User> queryUser();
}

 这个类就比较明显了,看到这里其实就说出了userMapper.xml所做的事情其实在这里只需要使用@Insert、@Select等等注解就可以了,然后写上相应的sql语句即可。

接下来是使用的方式:

package cn.bdx.testall;

import java.util.List;

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

import cn.bdx.dao.intf.UserDao;
import cn.bdx.model.User;
import cn.bdx.utils.DBFactory;

public class Main {

	@Test
	public void testAddUser() {
		User user = new User();
		user.setAge(11);
		user.setName("旺旺");
		
		SqlSession session = DBFactory.getSession();
		UserDao userDao = session.getMapper(UserDao.class);
		int count = userDao.addUser(user);
		if(count > 0) {
			System.out.println("添加成功");
		}else {
			System.out.println("添加失败");
		}
	}
	
	public static void main(String[] args) {
		User user = new User();
		user.setAge(11);
		user.setName("旺旺");
		
		SqlSession session = DBFactory.getSession();
		UserDao userDao = session.getMapper(UserDao.class);
		int count = userDao.addUser(user);
		if(count > 0) {
			System.out.println("添加成功");
		}else {
			System.out.println("添加失败");
		}
	}
	
	
	@Test
	public void testQueryAddUser() {
		SqlSession sqlSession = DBFactory.getSession();
		UserDao userDao = sqlSession.getMapper(UserDao.class);
		List<User> users = userDao.queryUser();
		System.out.println(users);
	}
}

 ----------------------------------------------------------------------------------------------------------------------------------

接下来看看mybatis多表操作吧。

多对一关系:一个teacher有多个student,具体代码如下:

conf.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 default="development">
		<environment id="development">
		   <!-- 配置事物 -->
		   <transactionManager type="JDBC" />
	       <!-- 配置数据库连接信息 -->
	       <dataSource type="POOLED">
	         <property name="driver" value="com.mysql.jdbc.Driver" />
	         <property name="url" value="jdbc:mysql://localhost:3306/school" />
	         <property name="username" value="root" />
	         <property name="password" value="a123" />
	       </dataSource>
		</environment>
	</environments>
	
	<mappers>
		<mapper resource="cn/bdx/mapper/teacherMapper.xml" />
	</mappers>

</configuration>

Teacher类:管理teacher与student之间的关系,在teacher类中有student的集合的属性

package cn.bdx.model;

import java.util.List;

public class Teacher {

	private int tid;
	private String tname;
	private String tsex;
	
	private List<Student> studentList;
	
	public List<Student> getStudentList() {
		return studentList;
	}
	public void setStudentList(List<Student> studentList) {
		this.studentList = studentList;
	}
	public int getTid() {
		return tid;
	}
	public void setTid(int tid) {
		this.tid = tid;
	}
	public String getTname() {
		return tname;
	}
	public void setTname(String tname) {
		this.tname = tname;
	}
	public String getTsex() {
		return tsex;
	}
	public void setTsex(String tsex) {
		this.tsex = tsex;
	}
	@Override
	public String toString() {
		return "Teacher [tid=" + tid + ", tname=" + tname + ", tsex=" + tsex
				+ ", studentList=" + studentList + "]";
	}
	
	
}

  Student类:

package cn.bdx.model;

public class Student {

	private int sid;
	private String sname;
	private int sage;
	public int getSid() {
		return sid;
	}
	public void setSid(int sid) {
		this.sid = sid;
	}
	public String getSname() {
		return sname;
	}
	public void setSname(String sname) {
		this.sname = sname;
	}
	public int getSage() {
		return sage;
	}
	public void setSage(int sage) {
		this.sage = sage;
	}
	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", sage=" + sage
				+ "]";
	}
	
	
}

 teacherMapper.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="cn.bdx.mapper.teacherMapper">
	<select id="queryTeacher" parameterType="int" resultMap="queryTeacherResults">
		select * from teacher_test t,student_test s where t.t_id=s.tid and t.t_id=#{tid}
	</select>
	<resultMap type="cn.bdx.model.Teacher" id="queryTeacherResults">
		<id property="tid" column="t_id"/>
		<result property="tname" column="t_name"/>
		<result property="tsex" column="t_sex"/>
		<collection property="studentList" ofType="cn.bdx.model.Student">
			<id property="sid" column="s_id"/>
			<result property="sname" column="s_name"/>
			<result property="sage" column="s_age"/>
		</collection>
	</resultMap>
</mapper>

  测试:

package cn.bdx.testall;

import java.util.List;

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

import cn.bdx.model.Teacher;
import cn.bdx.utils.DBFactory;


public class Main {

	@Test
	public void testQueryTeacher() {
		SqlSession session = DBFactory.getSession();
		List<Object> list = session.selectList("cn.bdx.mapper.teacherMapper.queryTeacher", 1);
		for (Object object : list) {
			Teacher teacher = (Teacher) object;
			System.out.println(teacher);
		}
	}
}

完毕,这是一个多对一关系的xml方式的写法,注意这里没有studentMapper.xml文件

一对多关系:还是teacher与student。

conf.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>
	<typeAliases>
		<typeAlias type="cn.bdx.model.Student" alias="Student"/>
		<typeAlias type="cn.bdx.model.Teacher" alias="Teacher"/>
	</typeAliases>
	
	
	<environments default="development">
		<environment id="development">
		   <!-- 配置事物 -->
		   <transactionManager type="JDBC" />
	       <!-- 配置数据库连接信息 -->
	       <dataSource type="POOLED">
	         <property name="driver" value="com.mysql.jdbc.Driver" />
	         <property name="url" value="jdbc:mysql://localhost:3306/school" />
	         <property name="username" value="root" />
	         <property name="password" value="a123" />
	       </dataSource>
		</environment>
	</environments>
	
	<mappers>
		<mapper resource="cn/bdx/mapper/studentMapper.xml" />
	</mappers>

</configuration>

Teahcer类:

package cn.bdx.model;


public class Teacher {

	private int tid;
	private String tname;
	private String tsex;
	
	public int getTid() {
		return tid;
	}
	public void setTid(int tid) {
		this.tid = tid;
	}
	public String getTname() {
		return tname;
	}
	public void setTname(String tname) {
		this.tname = tname;
	}
	public String getTsex() {
		return tsex;
	}
	public void setTsex(String tsex) {
		this.tsex = tsex;
	}
	@Override
	public String toString() {
		return "Teacher [tid=" + tid + ", tname=" + tname + ", tsex=" + tsex
				+ "]";
	}
	
	
}

 Student类:

package cn.bdx.model;

public class Student {

	private int sid;
	private String sname;
	private int sage;
	
	private Teacher teacher;
	
	
	public Teacher getTeacher() {
		return teacher;
	}
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}
	public int getSid() {
		return sid;
	}
	public void setSid(int sid) {
		this.sid = sid;
	}
	public String getSname() {
		return sname;
	}
	public void setSname(String sname) {
		this.sname = sname;
	}
	public int getSage() {
		return sage;
	}
	public void setSage(int sage) {
		this.sage = sage;
	}
	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", sage=" + sage
				+ ", teacher=" + teacher + "]";
	}
	
	
	
	
}

 这里使用Student类来管理teacher与student之间的关系,student类中有一个Teacher属性,对应的studentMapper.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="cn.bdx.mapper.studentMapper">
	<select id="queryStudent" parameterType="int" resultMap="queryStudentResults">
		select * from teacher_test t,student_test s where t.t_id=s.tid
	</select>
	<resultMap type="Student" id="queryStudentResults">
		<id property="sid" column="s_id"/>
		<result property="sname" column="s_name"/>
		<result property="sage" column="s_age"/>
		<association property="teacher" column="tid" javaType="Teacher">
			<id property="tid" column="t_id"/>
			<result property="tname" column="t_name"/>
			<result property="tsex" column="t_sex"/>
		</association>
	</resultMap>
</mapper>

 测试:

package cn.bdx.testall;

import java.util.List;

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

import cn.bdx.model.Student;
import cn.bdx.utils.DBFactory;


public class Main {

	@Test
	public void testQueryStudent() {
		SqlSession session = DBFactory.getInstance().getSession();
		List<Object> list = session.selectList("cn.bdx.mapper.studentMapper.queryStudent", 1);
		for (Object object : list) {
			Student teacher = (Student) object;
			System.out.println(teacher);
		}
	}
	
	public static void main(String[] args) {
		SqlSession session = DBFactory.getInstance().getSession();
		List<Object> list = session.selectList("cn.bdx.mapper.studentMapper.queryStudent", 1);
		for (Object object : list) {
			Student teacher = (Student) object;
			System.out.println(teacher);
		}
	}
}

 对于多对多或者一对一关系的操作基本上可以使用上面的方式进行变种既可以写出来,这里就不再详细记录了。

最后,贴上DBFactory类的代码吧:

package cn.bdx.utils;

import java.io.IOException;
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 DBFactory {
	private final String CONFIG_FILE_PATH = "conf.xml";
	private SqlSessionFactory factory = null;
	private SqlSession session = null;
	private static DBFactory instance = null;
	
	
	/**
	 * 获取SqlSessionFactory以及SqlSession对象
	 */
	private DBFactory() {
		Reader reader = null;
		try {
			reader = Resources.getResourceAsReader(CONFIG_FILE_PATH);
			factory = new SqlSessionFactoryBuilder().build(reader);
			session = factory.openSession();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 获取DBFactory的实例
	 * @return DBFactory的实例
	 */
	public static synchronized DBFactory getInstance() {
		if(instance == null) {
			synchronized (DBFactory.class) {
				instance = new DBFactory();
			}
		}
		return instance;
	}
	
	/**
	 * 获取SqlSession对象
	 * @return SqlSession对象
	 */
	public SqlSession getSession() {
		if(session == null) {
			throw new RuntimeException("Create SqlSession failed.");
		}
		return session;
	}
}

关于注解方式以后在来记录吧。

注:以上测试代码可以在我的csdn下面找得到,访问地址分别是:

单表xml:http://download.csdn.net/detail/mjcreator/9528305

单表注解:http://download.csdn.net/detail/mjcreator/9528322

多对一xml:http://download.csdn.net/detail/mjcreator/9528307

一对多xml:http://download.csdn.net/detail/mjcreator/9528327

 

 

分享到:
评论

相关推荐

    mybatis入门实例

    综上所述,"mybatis入门实例" 包含了 MyBatis 的核心概念和基本使用方法,通过对单表的 CRUD 操作,帮助初学者快速理解和掌握 MyBatis 的工作原理和实践技巧。在这个实例中,你可以看到从配置到实际操作的全过程,...

    MyBatis经典入门实例

    这个经典入门实例旨在为初学者提供一个快速理解MyBatis基本概念和操作方式的平台。通过学习这个实例,你可以掌握如何在实际项目中使用MyBatis进行数据操作。 首先,我们需要了解MyBatis的核心概念。MyBatis的核心是...

    MyBatis简单入门实例

    【标题】"MyBatis简单入门实例"是一个关于学习MyBatis基础操作的教程,适合初学者了解并实践这个流行的Java持久层框架。MyBatis是一个优秀的轻量级ORM(对象关系映射)框架,它简化了数据库操作,将SQL语句与Java...

    MyBatis入门实例源码

    在这个"MyBatis入门实例源码"中,我们可能看到以下几个关键的知识点: 1. **MyBatis基本概念**:MyBatis的核心组件包括SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession和Mapper接口。...

    springmvc+mybatis入门实例

    这个"springmvc+mybatis入门实例"提供了一个简单的SSM(Spring、Spring MVC、MyBatis)集成应用,旨在帮助初学者快速理解和上手这两个框架的结合。 首先,Spring MVC 框架的核心组件包括 DispatcherServlet、...

    Mybatis入门项目实例

    这个入门项目实例将带你深入了解Mybatis的核心概念和基本用法。首先,我们来分析一下提供的文件内容。 1. **用户指南(图片文件)** - `111115114.jpg`、`1.png`、`2.png`、`3.png`:这些很可能是项目教程或步骤的...

    mybatis入门实例(xml)

    在这个"mybatis入门实例(xml)"中,我们将探讨如何使用 MyBatis 的 XML 配置文件进行数据库操作。 首先,MyBatis 的核心是 SQL 映射文件,它位于项目的 resources 目录下,通常命名为 `mybatis-config.xml`。这个...

    mybatis入门实例(mysql数据库,带建表语句)

    总的来说,这个入门实例提供了一个基础的MyBatis使用模型,帮助初学者快速理解MyBatis如何与数据库交互。通过实践这个例子,你可以了解到MyBatis的配置、映射文件的编写、接口方法的定义以及如何在Java代码中调用...

    MyBatis入门实例详细代码

    【MyBatis入门实例详细代码】是一个针对初学者的教程,旨在帮助理解并掌握MyBatis框架的基础使用方法。MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射,避免了几乎所有的JDBC代码和手动设置...

    struts2+mybatis 入门实例

    但在这个入门实例中,我们仅关注Struts2和MyBatis的直接结合。 1. **环境准备**: - Java JDK:安装并配置好Java开发环境。 - 开发工具:IDEA或Eclipse等。 - Maven:用于依赖管理和构建项目。 2. **创建项目**...

    mybatis3.0.2入门实例

    在本入门实例中,我们将探讨如何使用MyBatis 3.0.2版本进行基本的数据库操作。这个实例适合初学者,将帮助你快速理解和掌握MyBatis的基本用法。 1. **MyBatis安装与配置** 在开始之前,确保你已经安装了JDK和Maven...

    Mybatis入门实例(二)——添加ehcache缓存支持

    在本篇《Mybatis入门实例(二)——添加ehcache缓存支持》中,我们将深入探讨如何在Mybatis框架中集成Ehcache作为二级缓存,以提高数据访问的效率和性能。Ehcache是一个开源的Java分布式缓存,广泛用于缓存应用程序中...

    MyBatis 入门实例 很详细很全面的中文文档

    **MyBatis 入门实例:非常详尽的中文教程** MyBatis 是一款流行的 Java 持久层框架,它允许开发者将 SQL 查询与 Java 代码直接绑定,提供了更灵活的数据访问方式,同时减轻了传统 JDBC 编程的繁琐工作。本教程将...

    mybatis入门实例(多对一xml)

    在这个“mybatis入门实例(多对一xml)”中,我们将深入探讨如何在MyBatis中处理多对一的关系映射,以及如何通过XML配置文件实现这种映射。 首先,多对一关系指的是在数据库设计中,一个实体(表)可以与多个其他实体...

    mybatis 入门实例

    本篇文章将深入解析mybatis入门实例的核心知识点,帮助初学者理解mybatis的基本使用方法,包括环境搭建、配置文件编写、实体类设计以及如何执行SQL查询。 ### 一、MyBatis简介 MyBatis是一款优秀的持久层框架,它...

    mybatis入门示例项目

    在本入门示例项目中,我们将深入理解MyBatis的基本使用方法,包括数据库交互、映射文件配置、配置文件加载、Junit测试以及日志记录。 1. 数据库SQL语句:MyBatis的核心功能之一就是将Java对象与数据库中的SQL语句...

    Mybatis入门实例(三)——使用MyBatis Generator生成DAO

    在本篇教程中,我们将深入探讨"Mybatis入门实例(三)——使用MyBatis Generator生成DAO"的主题。MyBatis Generator(MBG)是一个强大的工具,它可以自动生成MyBatis框架所需的代码,包括数据访问对象(DAO)、实体类...

    Mybatis入门实例(五)——MyBatis与Spring 3.X的整合

    8. 测试:编写测试类,使用Spring的ApplicationContext获取到Mapper接口的实例,然后调用其方法进行数据库操作。 在提供的`test.sql`文件中,可能包含了初始化数据库的数据,例如创建表、插入数据等操作,这是在...

    Mybits入门实例(实例免费下载!)

    这个入门实例将帮助初学者快速理解MyBatis的核心概念和使用方法。 首先,让我们从MyBatis的安装开始。要使用MyBatis,你需要在项目中引入MyBatis的jar包,这通常通过Maven或Gradle等构建工具完成。添加对应的依赖...

    源码:【Spring+MyBatis+MySQL实战入门】一、MyBatis操作入门

    《Spring+MyBatis+MySQL实战入门》系列教程旨在帮助初学者快速掌握这三大核心技术在实际项目中的应用。本文将重点讲解MyBatis操作入门的相关知识,通过源码解析,帮助你深入理解MyBatis的工作原理及使用方法。 1. ...

Global site tag (gtag.js) - Google Analytics