SpringBoot之数据访问和事务-专题三
SpringBoot之数据访问和事务-专题三
四、数据访问
4.1、springboot整合使用JdbcTemplate
4.1.1 pom文件引入
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<!-- jdbcTemplate 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- springboot-web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
4.1.2 application.properties新增配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
4.1.3 UserService类
@Service
public class UserServiceImpl implements UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public void createUser(String name, Integer age) {
jdbcTemplate.update("insert into users values(null,?,?);", name, age);
}
}
4.1.4 App类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
注意: spring-boot-starter-parent要在1.5以上
4.2、springboot整合使用mybatis
4.2.1、pom文件引入
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- springboot-web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
4.2.2、配置文件引入
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
4.2.3、Mapper代码
public interface UserMapper {
@Select("SELECT * FROM USERS WHERE NAME = #{name}")
User findByName(@Param("name") String name);
@Insert("INSERT INTO USERS(NAME, AGE) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);
}
4.2.4、启动方式
@MapperScan("com.mapper")
@SpringBootApplication
public class MybatisApp {
public static void main(String[] args) {
SpringApplication.run(MybatisApp.class, args);
}
}
4.2.5、Mybatis整合分页插件
pageHelper
PageHelper 是一款好用的开源免费的 Mybatis 第三方物理分页插件
物理分页
支持常见的 12 种数据库。Oracle,MySql,MariaDB,SQLite,DB2,PostgreSQL,SqlServer 等
支持多种分页方式
支持常见的 RowBounds(PageRowBounds),PageHelper.startPage 方法调用,Mapper 接口参数调用
Maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- springboot-web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot 整合 pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
</dependencies>
配置文件
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
logging.level.com.example.demo.dao=DEBUG
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
pagehelper.page-size-zero=true
Entity层
@Data
public class User {
private Integer id;
private String name;
private Integer age;
}
Mapper层
public interface UserMapper {
@Select("SELECT * FROM USERS ")
List<User> findUserList();
}
Service层
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public PageInfo<User> findUserList(int page, int size) {
// 开启分页插件,放在查询语句上面
PageHelper.startPage(page, size);
List<User> listUser = userMapper.findUserList();
// 封装分页之后的数据
PageInfo<User> pageInfoUser = new PageInfo<User>(listUser);
return pageInfoUser;
}
}
Controller层
@RestController
public class IndexController {
@Autowired
private UserService userService;
@RequestMapping("/findUser")
public PageInfo<User> findUserList(int page, int size) {
return userService.findUserList(page, size);
}
}
启动项目
@MapperScan("com.mapper")
@SpringBootApplication
public class PageHelper {
public static void main(String[] args) {
SpringApplication.run(PageHelper.class, args);
}
}
4.3、springboot整合使用springjpa
4.3.1 pom文件引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
4.3.2 创建User实体类
@Entity(name = "users")
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
}
4.3.3 创建UserDao
public interface UserDao extends JpaRepository<User, Integer> {
}
4.3.3 创建IndexController
@RestController
public class IndexController {
@Autowired
private UserDao userDao;
@RequestMapping("/jpaFindUser")
public Object jpaIndex(User user) {
Optional<User> userOptional = userDao.findById(user.getId());
User reusltUser = userOptional.get();
return reusltUser == null ? "没有查询到数据" : reusltUser;
}
}
4.3.4 启动项目
@SpringBootApplication
public class JpaApp {
public static void main(String[] args) {
SpringApplication.run(JpaApp.class, args);
}
}
4.4、springboot整合多数据源
思考下,你们在项目中有使用到多数据源吗?
原理使用根据包名,加载不同的数据源
4.4.1配置文件中新增两个数据源
###datasource1
spring.datasource.test1.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.test1.jdbc-url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
spring.datasource.test1.username = root
spring.datasource.test1.password = root
###datasource2
spring.datasource.test2.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.test2.jdbc-url = jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
spring.datasource.test2.username = root
spring.datasource.test2.password = root
4.4.2配置文件中新增两个数据源
//DataSource01
@Configuration // 注册到springboot容器中
@MapperScan(basePackages = "com.example.test01", sqlSessionFactoryRef = "test1SqlSessionFactory")
public class DataSource1Config {
@Bean(name = "test1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.test1")
@Primary
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "test1SqlSessionFactory")
@Primary
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// bean.setMapperLocations(
// new
// PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test1/*.xml"));
return bean.getObject();
}
@Bean(name = "test1TransactionManager")
@Primary
public DataSourceTransactionManager testTransactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test1SqlSessionTemplate")
@Primary
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
DataSource02
//DataSource2
@Configuration // 注册到springboot容器中
@MapperScan(basePackages = "com.example.test02", sqlSessionFactoryRef = "test2SqlSessionFactory")
public class DataSource2Config {
@Bean(name = "test2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.test2")
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// bean.setMapperLocations(
// new
// PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test2/*.xml"));
return bean.getObject();
}
@Bean(name = "test2TransactionManager")
public DataSourceTransactionManager testTransactionManager(@Qualifier("test2DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
4.4.2创建分包Mapper
public interface User1Mapper {
@Insert("insert into users values(null,#{name},#{age});")
public int addUser(@Param("name") String name, @Param("age") Integer age);
}
4.4.3 多数据源事务注意事项
在多数据源的情况下,使用@Transactional注解时,应该指定事务管理者
@Transactional(transactionManager = “test2TransactionManager”)
4.4.5启动项目
@SpringBootApplication
@MapperScan(basePackages = { "com.example.mapper" })
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: test1DataSource,test2DataSource
加上@Primary即可。
There was an unexpected error (type=Internal Server Error, status=500).
No qualifying bean of type ‘org.springframework.transaction.PlatformTransactionManager’ available: expected single matching bean but found 2: test1TransactionManager,test2TransactionManager
指定事务管理器
Springboot1.5的时候 没有默认指向数据源 会报错
Springboot2.0的时候 不报错
五、事物管理
5.1.1SpringBoot整合事物管理
Springboot默认集成事物,只主要在方法上加上@Transactional即可
5.1.2SpringBoot分布式事物管理
使用springboot+jta+atomikos 分布式事物管理
Atomikos 是一个为Java平台提供增值服务的并且开源类事务管理器。
5.1.2.1 新增jta-atomikos依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
5.1.2.2新增配置文件信息
# Mysql 1
mysql.datasource.test1.url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test1.username = root
mysql.datasource.test1.password = root
mysql.datasource.test1.minPoolSize = 3
mysql.datasource.test1.maxPoolSize = 25
mysql.datasource.test1.maxLifetime = 20000
mysql.datasource.test1.borrowConnectionTimeout = 30
mysql.datasource.test1.loginTimeout = 30
mysql.datasource.test1.maintenanceInterval = 60
mysql.datasource.test1.maxIdleTime = 60
# Mysql 2
mysql.datasource.test2.url =jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test2.username =root
mysql.datasource.test2.password =root
mysql.datasource.test2.minPoolSize = 3
mysql.datasource.test2.maxPoolSize = 25
mysql.datasource.test2.maxLifetime = 20000
mysql.datasource.test2.borrowConnectionTimeout = 30
mysql.datasource.test2.loginTimeout = 30
mysql.datasource.test2.maintenanceInterval = 60
mysql.datasource.test2.maxIdleTime = 60
5.1.2.3 读取配置文件信息
@Data
@ConfigurationProperties(prefix = "mysql.datasource.test1")
public class DBConfig1 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
@Data
@ConfigurationProperties(prefix = "mysql.datasource.test2")
public class DBConfig2 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
5.1.2.4 创建多数据源
@Configuration
// basePackages 最好分开配置 如果放在同一个文件夹可能会报错
@MapperScan(basePackages = "com.example.test01", sqlSessionTemplateRef = "testSqlSessionTemplate")
public class MyBatisConfig1 {
// 配置数据源
@Primary
@Bean(name = "testDataSource")
public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("testDataSource");
xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
}
@Primary
@Bean(name = "testSqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Primary
@Bean(name = "testSqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@Configuration
@MapperScan(basePackages = "com.example.test02", sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class MyBatisConfig2 {
// 配置数据源
@Bean(name = "test2DataSource")
public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("test2DataSource");
xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
}
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
5.1.2.4 启动加载配置
@EnableConfigurationProperties(value = { DBConfig1.class, DBConfig2.class })
分布式事务,可以预览我的这个链接分布式事务
SpringBoot之数据访问和事务-专题三的更多相关文章
- Solon Web 开发,五、数据访问、事务与缓存应用
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Spring数据访问和事务
1.模型 2.解耦 3.实现 3.1 核心接口 3.2 代码分析 3.2.1 事务管理 3.2.2 数据访问 4.使用 4.1 编程模式 4.2 配置模式 4.2.1 声明式配置方式 4.2.2 注解 ...
- 六、SpringBoot与数据访问
六.SpringBoot与数据访问 1.JDBC spring: datasource: username: root password: 123456 url: jdbc:mysql://192.1 ...
- SpringBoot(九) -- SpringBoot与数据访问
一.简介 对于数据访问层,无论是SQL还是NOSQL,Spring Boot默认采用整合Spring Data的方式进行统一处理,添加大量自动配置,屏蔽了很多设置.引入各种xxxTemplate,xx ...
- 10分钟进阶SpringBoot - 05. 数据访问之JDBC(附加源码分析+代码下载)
10分钟进阶SpringBoot - 05. 数据访问之JDBC 代码下载:https://github.com/Jackson0714/study-spring-boot.git 一.JDBC是什么 ...
- Spring ( 五 )Spring之数据访问与事务管理
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.Spring之数据访问 1.Spring数据访问工程环境搭建 jdbc.properties配置 ...
- java框架之SpringBoot(9)-数据访问及整合MyBatis
简介 对于数据访问层,无论是 SQL 还是 NOSQL,SpringBoot 默认采用整合 SpringData 的方式进行统一处理,添加了大量的自动配置,引入了各种 Template.Reposit ...
- Spring 4 官方文档学习(九)数据访问之事务管理
说明:未整理版,未完待续,请绕行 本部分的重点是数据访问以及数据访问层与业务层之间的交互. 1.Spring框架的事务管理 介绍 http://docs.spring.io/spring/docs/c ...
- SpringBoot 之数据访问
1. Spring Boot 与 JDBC 默认使用 org.apache.tomcat.jdbc.pool.DataSource 数据源; // application.yml spring: da ...
随机推荐
- Speech Bandwidth Extension With WaveNet
利用WAVENET扩展语音带宽 作者:Archit Gupta, Brendan Shillingford, Yannis Assael, Thomas C. Walters 博客地址:https:/ ...
- GO学习之 从hello.go开始
一.GO运行的两种方式 1.如果是对源码编译后,再执行 如:hello.go文件 hello.go文件(源文件)----go build hello.go[编译文件]--->变成可执行文件(.e ...
- Visual Studio Code打不开
1.win+R 2.输入cmd 3.输入netsh winsock reset然后就可以打开了,如果依然打不开就重启电脑试试
- C#面向对象三大特性:继承
什么是继承 定义:继承是面向对象编程语言中的一个重要特性,当一个类A能够获取另一个类B中所有非私有的数据和操作的定义作为自己的部分或全部成分时,就称这两个类之间具有继承关系.被继承的类B称为父类或基类 ...
- Git主库私库相关操作操作
命令1: git remote add 库名称 库地址 说明:写好的代码提交到两个git远端,git remote add是将另一个库地址设置进来 命令2: git fetch 库名称 分支名称 说明 ...
- redis(一)动态字符串
redis 动态字符串 概述 Sda(Simple Dynamic String) 简单动态字符串是 redis中用来表示字符串的结构,而不是传统 C 字符串. 主要的特点就是Sda要做到高效和 二进 ...
- idea新建maven project工程
1.new project: 2.新建在main 下新建 java directory 并mark as source root,这里我已经makr过java目录所以以showfor做演示: 3.新 ...
- Centos610安装Jdk1.8
1.下载JDK 下载: https://pan.baidu.com/s/15TYsE_wfSb48pS4SpUQKHA 提取码:fsx6 2.上传安装包 上传到linux 并拷贝到/opt/jdk目 ...
- 卸载mysql时,提示libmysqlclient.so.16()(64bit) is needed by (installed) postfix
卸载时,提示错误,用这个命令就可以rpm -e --nodeps mysql-libs-5.1.73-5.el6_6.x86_64(这个是自己要卸载的版本) [root@unaryhost dev]# ...
- loadrunner测试sql语句性能
最初的想法是是想通过录制在SQL Server2008的操作来着的,无奈试了即便都录不到查询的sql语句,网上查资料全是关于SQL 2000的(这部分有经验的欢迎指教). 于是只能通过直接调用load ...