深入浅出 MyBatis | CRUD 操作、配置解析
3、CRUD
3.1 namespace
namespace 中的包名要和 Dao/Mapper 接口的包名一致!
比如将 UserDao 改名为 UserMapper
运行发现抱错,这是因为 UserMapper.xml 中没有同步更改 namespace
成功运行
给出 UserMapper 中的所有接口,接下来一一对这些接口实现 CRUD 操作
pojo 下对应的数据库表的实体类 User
说明:下述的 sql 语句中的如:
select * from mybatis.user
,其中 mybatis.user 的 mybatis 是我定义的数据库的名,如果你的数据库名为 xxx,因为为select * from xxx.user
3.2 select
选择,查询语句;
- id:就是对应的 namespace 中的方法名;、
- resultType:Sql 语句执行的返回值!
- parameterType:参数类型!
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><select id="getUserList" resultType="com.uestc.pojo.User">select * from mybatis.user</select>
</mapper>
接下来实现根据 ID 查询用户
在 UserMapper 接口中加入方法
// 根据 ID 查询用户
User getUserById(int id);
在 UserMapper.xml 中配置
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><select id="getUserById" parameterType="int" resultType="com.uestc.pojo.User">select * from mybatis.user where id = #{id}</select></mapper>
- id=“getUserById” 对应 UserMapper 接口中 getUserById 方法
- parameterType 为传入的参数 int id;
- resultType 为返回的类型 User
- select * from mybatis.user where id = #{id},其中 #{} 表示取值,传入 id 这个参数,然后 #{id} 取出即可,注意是花括号,不是圆括号
在 test 中进行测试
@Test
public void getUserByIdTest() {//第一步:获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.getUserById(1); // 查询 id = 1 的用户System.out.println(user);//关闭SqlSessionsqlSession.close();
}
3.3 Insert(增)
在 UserMapper 接口中加入方法 addUser
//插入一个用户
int addUser(User user);
在 UserMapper.xml 中配置(插入操作的 sql 语句为:INSERT INTO students (id, name, age) VALUES (1, 'Alice', 20);
)
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><!-- 对象中的属性可以直接取出--><insert id="addUser" parameterType="com.uestc.pojo.User">insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd})</insert></mapper>
- insert 标签用于插入,其中实体类 User 中的属性可以直接通过属性名获取:
#{id}, #{name}, #{pwd}
在 test 中进行测试
@Test
public void addUserTest() {SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.addUser(new User(4, "哈哈", "123456"));sqlSession.close();
}
执行
刷新数据库,没有看到
那是因为数据库增删改一定要提交事务 sqlSession.commit();
@Test
public void addUserTest() {SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);int res = mapper.addUser(new User(4, "哈哈", "123456"));if (res > 0) {System.out.println("插入成功!");}// 提交事务sqlSession.commit();sqlSession.close();
}
成功插入!
3.4 Update(改)
在 UserMapper 接口中加入方法 updateUser
int updateUser(User user);
在 UserMapper.xml 中配置
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><update id="updateUser" parameterType="com.uestc.pojo.User">update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id}</update></mapper>
- update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id},之前 sql 中是直接 set 赋值,在这里,直接将 User 实例中的属性赋过去即可,即 name=#{name},pwd=#{pwd} where id = #{id}
测试:注意一定要提交事务
@Test
public void updateUserTest() {SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);int res = mapper.updateUser(new User(4, "啊啊", "12345678"));// 提交事务sqlSession.commit();sqlSession.close();
}
3.5 Delete(删)
在 UserMapper 接口中加入方法 deleteUser
int deleteUser(int id);
在 UserMapper.xml 中配置
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><delete id="deleteUser" parameterType="int">delete from mybatis.user where id = #{id}</delete></mapper>
测试:
@Testpublic void deleteUserTest() {SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);int res = mapper.deleteUser(4);// 提交事务sqlSession.commit();sqlSession.close();}
注意点:
- 增删改需要提交事务!
3.6 分析错误
- xml 文件中注释不能出现中文报错,查看自己的是UTF-8还是GBK编码,改成为相应的就行。
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="GBK" ?>
即可成功测试。
-
标签不要匹配错!
-
resource绑定mapper,需要使用路径!
-
程序配置文件必须符合规范!
-
NullPointerException,没有注册到资源!
-
maven资源没有导出问题!
3.7 万能 Map(企业中常用)
假设,实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map!
比如在 UserMapper 接口中加入方法 addUser2。用 Map 作为参数来传,不需要知道数据库内有什么
// 万能的Map
int addUser2(Map<String,Object> map); // 同 int addUser(User user); 功能
在 UserMapper.xml 中配置
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><!--对象中的属性,可以直接取出来 传递map的key--><insert id="addUser2" parameterType="map">insert into mybatis.user (id, pwd) values (#{userid},#{password})</insert></mapper>
老方式:
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><!-- 对象中的属性可以直接取出--><insert id="addUser" parameterType="com.uestc.pojo.User">insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd})</insert></mapper>
- 对比之前添加用户注册的值,之前没有 map 参数时,传入的值
#{id}, #{name}, #{pwd}
必须与实体的属性一致,而使用 map 后,随意传入什么都可以,因为传递的是 map 的 key,不需要与数据库中的表的属性一致,传入什么都可以#{userid}, #{password}
- 这里与之前的老方式比较:某个key省去都不影响,比如 #{userid},#{password},没有 name 了。这就可以应付参数过多的情况,并不需要写出所有参数
测试
@Test
public void addUser2Test() {SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String,Object> map = new HashMap<String, Object>();map.put("userid", 4);map.put("password","123321");mapper.addUser2(map);// 提交事务sqlSession.commit();sqlSession.close();
}
再来看对上面 User getUserById(int id); 用 map 作为参数传递
User getUserById2(Map<String,Object> map);
在 UserMapper.xml 中配置
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><select id="getUserById2" parameterType="map" resultType="com.uestc.pojo.User">select * from mybatis.user where id = #{helloid} and name = #{helloname}</select></mapper>
- id = #{helloid} and name = #{helloname} 这里 helloid 和 helloname 都可以任意,但是用之前的方式,这里就限制死了,必须要实体类和数据库属性一致
测试
@Test
public void getUserById2Test() {SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String,Object> map = new HashMap<String, Object>();map.put("helloid", 1);map.put("helloname", "洪");User user = mapper.getUserById2(map);System.out.println(user);// 提交事务sqlSession.commit();sqlSession.close();
}
Map传递参数,直接在sql中取出key即可!【parameterType=“map”】
对象传递参数,直接在sql中取对象的属性即可!【parameterType=“Object”】
只有一个基本类型参数的情况下,可以直接在sql中取到!
多个参数用Map,或者注解!
3.8 思考题
模糊查询怎么写?
1. java 代码执行的时候,传递通配符% %
UserMapper 接口中加入方法 getUserLike
List<User> getUserLike(String value);
在 UserMapper.xml 中配置
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><select id="getUserLike">select * from mybatis.user where name like "%"#{value}"%"</select></mapper>
"%"#{value}"%"
,其中 value 就是要传入的值,这样传入可能导致 SQL 注入问题
测试
@Test
public void getUserLikeTest() {//第一步:获得SqlSession对象SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.getUserLike("%李%");for (User user : userList) {System.out.println(user);}//关闭SqlSessionsqlSession.close();
}
4、配置解析
4.1 核心配置文件
- mybatis-config.xml
- MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
只需掌握红色圈起来的即可,其他了解
4.2 环境配置(environments)
-
Mybatis 可以配置成适应多种环境
-
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
-
学会使用配置多套运行环境!
-
Mybatis默认的事务管理器就是 JDBC, 连接池:POOLED
了解事物管理器,不只有 JDBC 还有 MANAGED
了解什么是数据源(dataSource),作用只有一个:连接数据库
在 MyBatis 中,dataSource
和 transactionManager
是两个重要的概念,分别用于数据库连接管理和事务控制。
1. DataSource(数据源)
DataSource
是指数据库连接池的配置和管理组件,它负责提供数据库连接。使用数据源可以提高应用程序对数据库连接的管理效率,避免每次操作都重新创建数据库连接。
在 MyBatis 中,DataSource
主要用于管理与数据库的连接。常见的数据源类型有:
- DriverManagerDataSource:最简单的数据源,直接使用 JDBC 驱动来建立数据库连接。
- BasicDataSource(来自 Apache Commons DBCP)和 HikariCP:更常用的连接池实现,通过池化技术来提高性能。
MyBatis 通过配置 dataSource
来指定如何连接到数据库。通常会在 mybatis-config.xml
或 Spring 配置文件中进行配置。例如:
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/><property name="username" value="root"/><property name="password" value="password"/>
</dataSource>
2. TransactionManager(事务管理器)
TransactionManager
是 MyBatis 中的事务控制组件,用于管理数据库事务的开始、提交和回滚。它帮助开发者处理事务的生命周期,并确保事务在正确的时机进行提交或回滚。
在 MyBatis 中,TransactionManager
有两种常见的实现:
- JDBCTransaction:通过 JDBC 来管理事务,适用于不使用 Spring 等容器的简单项目。
- ManagedTransaction:通过外部容器(如 Spring)来管理事务,适用于集成到 Spring 框架的应用。
如果使用 Spring 框架,MyBatis 通常会与 Spring 的事务管理器集成,使用 SpringManagedTransaction
来管理事务。在 Spring 环境中,事务管理器可以通过 @Transactional
注解来控制事务的提交和回滚。
示例配置:
<transactionManager type="JDBC"><!-- JDBC事务管理器配置 -->
</transactionManager>
或在 Spring 中:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean>
小结:
- DataSource:用于数据库连接池的管理,提供数据库连接。
- TransactionManager:用于事务的管理,控制事务的开启、提交和回滚。
这两个组件在 MyBatis 中共同工作,以保证应用程序能够高效且安全地与数据库进行交互,同时确保事务的一致性。
标签顺序
在 MyBatis 配置文件中,XML 标签的顺序通常是固定的,遵循一定的逻辑结构,确保各个组件按正确的顺序初始化。下面是常见的 mybatis-config.xml
配置文件中的标签顺序及其含义:
1. <?xml version="1.0" encoding="UTF-8"?>
这是 XML 文件的声明部分,通常位于文件的开头。
2. <configuration>
<configuration>
是 MyBatis 配置文件的根标签,所有其他标签都在这个标签内。
<configuration><!-- 配置内容 -->
</configuration>
3. <properties>
(可选)
在配置文件的开始部分,可以定义一些外部属性,这些属性可以在整个配置文件中引用。通常用于配置数据库连接信息等。
<properties><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/><property name="username" value="root"/><property name="password" value="password"/>
</properties>
4. <settings>
<settings>
标签用于配置 MyBatis 的全局设置,例如缓存开关、懒加载等。
<settings><setting name="cacheEnabled" value="true"/><setting name="lazyLoadingEnabled" value="false"/><setting name="multipleResultSetsEnabled" value="true"/>
</settings>
5. <typeAliases>
<typeAliases>
标签用于定义类型别名,可以为 Java 类创建简化的别名。
在 MyBatis 中,<typeAliases>
标签可以通过两种方式为 Java 类型创建别名:一种是为单个类型设置别名,另一种是为整个包中的所有类创建别名。两种方式的配置如下:
- 单个类型设置别名
<typeAliases><typeAlias alias="User" type="com.example.User"/>
</typeAliases>
- 为整个包设置别名
另一种方式是为整个包中的所有类创建别名,MyBatis 会自动为该包中的每个类生成别名。默认情况下,MyBatis 会使用类名的首字母小写作为别名(但你也可以通过 <typeAlias>
标签自定义别名)。
<typeAliases><package name="com.uestc.pojo"/>
</typeAliases>
- name:指定了要扫描的包路径,这里是
com.uestc.pojo
包。
此配置告诉 MyBatis 扫描 com.uestc.pojo
包中的所有类,并自动为每个类创建别名。默认情况下,MyBatis 会将每个类名的首字母转换为小写,并将其作为别名。例如:
com.uestc.pojo.User
类的别名将自动生成为user
。com.uestc.pojo.Order
类的别名将自动生成为order
。
6. <typeHandlers>
(可选)
<typeHandlers>
标签用于配置自定义的类型处理器。类型处理器用于在 Java 类型与 JDBC 类型之间转换。
<typeHandlers><typeHandler handler="com.example.CustomTypeHandler"/>
</typeHandlers>
7. <objectFactory>
(可选)
<objectFactory>
标签用于指定自定义的对象工厂,用于 MyBatis 实例化对象。
<objectFactory type="com.example.CustomObjectFactory"/>
8. <plugins>
(可选)
<plugins>
标签用于配置 MyBatis 插件,例如分页插件、性能分析插件等。
<plugins><plugin interceptor="org.mybatis.example.PluginExample"/>
</plugins>
9. <environments>
<environments>
标签用于定义多个环境(例如开发环境、生产环境),每个环境可以指定不同的数据源和事务管理器。
<environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/><property name="username" value="root"/><property name="password" value="password"/></dataSource></environment>
</environments>
10. <mappers>
<mappers>
标签用于指定映射器(Mapper)的配置,可以是 .xml
文件的路径,也可以是 Mapper 接口的类名。
<mappers><mapper resource="com/example/mapper/UserMapper.xml"/><mapper class="com.example.mapper.ProductMapper"/>
</mappers>
总体结构
根据上述内容,MyBatis 的配置文件通常遵循以下顺序:
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!-- 可选的外部属性 --><properties><!-- 配置项 --></properties><!-- 全局设置 --><settings><!-- 设置项 --></settings><!-- 类型别名 --><typeAliases><!-- 别名配置 --></typeAliases><!-- 类型处理器 --><typeHandlers><!-- 自定义类型处理器 --></typeHandlers><!-- 对象工厂 --><objectFactory><!-- 自定义对象工厂 --></objectFactory><!-- 插件 --><plugins><!-- 插件配置 --></plugins><!-- 环境设置 --><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!-- 数据源配置 --></dataSource></environment></environments><!-- 映射器配置 --><mappers><mapper resource="com/example/mapper/UserMapper.xml"/><mapper class="com.example.mapper.ProductMapper"/></mappers></configuration>
小结:
在 MyBatis 的配置文件中,标签的顺序通常为:
properties
(可选)settings
typeAliases
typeHandlers
(可选)objectFactory
(可选)plugins
(可选)environments
mappers
标签顺序通常没有严格的约束,但遵循这个顺序可以使配置文件更加清晰易懂。
新建项目 Mybatis-02
将 Mybatis-01 中所有的环境都打包过来,然后删除掉部分内容,使其简洁
UserMapper 只保留这几个基本方法,并删除相应的 UserMapper.xml 中的配置
测试 UserDaoTest 只留一个
4.3 属性(properties)
我们可以通过properties属性来实现引用配置文件
这些属性都是可外部配置且可动态替换的,既可以在典型的Java属性文件中配置,亦可通过properties元素的子元素来传递。【db.properties】
编写一个配置文件 db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://112.124.60.179:3310/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
在核心配置文件中映入
<!--引入外部配置文件-->
<properties resource="db.properties"><property name="username" value="root"/><property name="pwd" value="123123"/>
</properties>
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的!
标签是有放的顺序的,必须保证这个顺序,所以 properties 是放在最上面
mybatis-config.xml 更改如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration core file-->
<configuration><!--引入外部配置文件--><properties resource="db.properties">
<!-- <property name="username" value="root"/>-->
<!-- <property name="pwd" value="123456"/>--></properties><environments default="development"><environment id="development"><!--事务管理--><transactionManager type="JDBC"/><dataSource type="POOLED"><!--数据库相关配置--><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--每一个 Mapper.xml 都需要在 Mybatis 核心配置文件(mybatis-config.xml) 中注册!--><mappers><mapper resource="com/uestc/dao/UserMapper.xml"/></mappers></configuration>
运行测试,成功
同时可以 properties 中写一部分 db.properties 中写一部分
mybatis-config.xml 更改如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration core file-->
<configuration><!--引入外部配置文件--><properties resource="db.properties"><property name="username" value="root"/><property name="pwd" value="123456"/></properties><environments default="development"><environment id="development"><!--事务管理--><transactionManager type="JDBC"/><dataSource type="POOLED"><!--数据库相关配置--><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${pwd}"/></dataSource></environment></environments><!--每一个 Mapper.xml 都需要在 Mybatis 核心配置文件(mybatis-config.xml) 中注册!--><mappers><mapper resource="com/uestc/dao/UserMapper.xml"/></mappers></configuration>
properties 和 db.properties 如果都有相同的字段,比如 username 和 password,就存在优先级的问题
测试成功出结果,说明优先使用的是 db.properties 里面的
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件的 !
4.4 类型别名(typeAliases)[ˈeɪliəsɪz] 别名
- 类型别名是为Java类型设置一个短的名字。
- 存在的意义仅在于用来减少类完全限定名的冗余。
mybatis-config.xml 中取别名
<!--可以给实体类起别名-->
<typeAliases><typeAlias type="com.uestc.pojo.User" alias="User" />
</typeAliases>
注意 typeAliases 标签放置得位置顺序
UserMapper.xml 中使用
<!--namespace绑定一个对应的 Dao/Mapper 接口-->
<mapper namespace="com.uestc.dao.UserMapper"><!--sql查询语句,getUserList 以前需要放到 UserDaoImpl实现类中重写,现在只需要标签即可--><select id="getUserList" resultType="User">select * from mybatis.user</select></mapper>
执行测试
也可以指定一个包名,MyBatis会在包名下面搜索需要的 JavaBean,比如:
扫描实体类的包,它的默认别名就为这个类的类名,首字母小写!(比如类名为 User,替换时用 user 也可以跑出来)
<!--可以给实体类起别名-->
<typeAliases><package name="com.uestc.pojo"/>
</typeAliases>
下面大写小写首字母都可以运行成功,推荐使用首字母小写
在实体类比较少的时候,使用第一种方式。
如果实体类十分多,建议使用第二种。
第一种可以DIY别名,第二种则不行,如果非要改,需要在实体上增加注解,见下:(即在第二种方式的基础上,增加注解)
@Alias("user")
//实体类
public class User {xxx}
测试
原因是通过注解更改了别名,所以要用 hello
4.5 设置
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
4.6 其他配置
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- mybatis-generator-core
- mybatis-plus
- 通用mapper
4.7 映射器(mappers)
MapperRegistry:注册绑定我们的 Mapper 文件;
方式一:【推荐使用】 在 mybatis-config.xml 中加入如下:
<!--每一个 Mapper.xml 都需要在 Mybatis 核心配置文件(mybatis-config.xml) 中注册!-->
<mappers><mapper resource="com/uestc/dao/UserMapper.xml"/>
</mappers>
将 UserMapper.xml 文件放入到其他地方,同时更改 mapper 标签下路径,可以正常运行
方式二:使用 class 文件绑定注册
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers><mapper class="com.uestc.dao.UserMapper"/>
</mappers>
将 UserMapper.xml 文件放入到其他地方,同时更改 mapper 标签下路径,运行失败
将 UserMapper.xml 与其绑定得接口 UserMapper 放在同一个包下,运行成功
因此第二个方式注意点:
- 接口和它的Mapper配置文件必须同名!
- 接口和它的Mapper配置文件必须在同一个包下!
方式三:使用扫描包进行注入绑定
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
<mappers><package name="com.uestc.dao"/>
</mappers>
方式三注意点:
- 接口和它的Mapper配置文件必须同名!
- 接口和它的Mapper配置文件必须在同一个包下!
4.8 生命周期和作用域
生命周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder:
- 一旦创建了 SqlSessionFactory,就不再需要它了。
- 局部变量
SqlSessionFactory:
- 说白就是可以想象为:数据库连接池。
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- SqlSessionFactory 的最佳作用域是应用作用域。
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession:
- 连接到连接池的一个请求!
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 用完后需要赶紧关闭,否则资源被占用!
这里的每一个Mapper,就代表一个具体的业务!
相关文章:
深入浅出 MyBatis | CRUD 操作、配置解析
3、CRUD 3.1 namespace namespace 中的包名要和 Dao/Mapper 接口的包名一致! 比如将 UserDao 改名为 UserMapper 运行发现抱错,这是因为 UserMapper.xml 中没有同步更改 namespace 成功运行 给出 UserMapper 中的所有接口,接下来一一对…...
Hutool 发送 HTTP 请求的几种常见写法
最简单的 GET 请求: String result HttpUtil.get("https://www.baidu.com");带参数的 GET 请求: // 方法1: 直接拼接URL参数 String result HttpUtil.get("https://www.baidu.com?name张三&age18");// 方法2: 使用 HashMap…...
计算机网络|数据流向剖析与分层模型详解
文章目录 一、网络中的数据流向二、计算机网络通信模型1.OSI 模型2.TCP/IP 模型3.TCP/IP五层模型3.1 分层架构描述3.2各层地址结构3.3UDP数据包报头结构 三、总结 一、网络中的数据流向 在计算机网络中,数据的流向是指数据从发送端到接收端的传输路径。数据流向涉及…...
在Java技术栈中,常用的分布式一致性算法和框架
在Java技术栈中,常用的分布式一致性算法和框架包括: Raft算法: 常用框架: etcd:虽然主要用Go语言编写,但可以通过Java客户端进行访问和操作。Apache Kafka:在其控制器选举中使用类似Raft的机…...
2024.12.29(进程线程实现并发服务器)
作业 多进程多线程并发服务器实现一遍提交。 服务器 #include <myhead.h> #define PORT 12345 #define IP "192.168.124.123"void *fun(void *fd) {int newfd *(int *)fd;char buff[1024];while(1){int res recv(newfd,buff,sizeof(buff),0);if(res 0){p…...
Docker完整技术汇总
Docker 背景引入 在实际开发过程中有三个环境,分别是:开发环境、测试环境以及生产环境,假设开发环境中开发人员用的是jdk8,而在测试环境中测试人员用的时jdk7,这就导致程序员开发完系统后将其打成jar包发给测试人员后…...
区块链安全常见的攻击合约和简单复现,附带详细分析——不安全调用漏洞 (Unsafe Call Vulnerability)【6】
区块链安全常见的攻击分析——不安全调用漏洞 Unsafe Call Vulnerability 区块链安全常见的攻击合约和简单复现,附带详细分析——不安全调用漏洞 (Unsafe Call Vulnerability)【6】1.1 漏洞合约1.2 漏洞分析1.3 攻击步骤分析1.4 攻击合约 区块链安全常见的攻击合约和…...
Vue.js 高难度组件开发:从插件化到性能极限优化
Vue.js 高难度组件开发:从插件化到性能极限优化 引言一、插件化组件开发1. 什么是插件化组件2. 案例:构建一个插件化的图表组件 二、动态扩展与自定义组件行为1. 动态添加组件功能 三、复杂交互与细粒度状态管理1. 使用 Vuex 的模块化和动态模块注册 四、…...
一个通用的居于 OAuth2的API集成方案
在现代 web 应用程序中,OAuth 协议是授权和认证的主流选择。为了与多个授权提供商进行无缝对接,我们需要一个易于扩展和维护的 OAuth 解决方案。本文将介绍如何构建一个灵活的、支持多提供商的 OAuth 系统,包括动态 API 调用、路径参数替换、…...
折腾日记:如何让吃灰笔记本发挥余热——搭建一个相册服务
背景 之前写过,我在家里用了一台旧的工作站笔记本做了服务器,连上一个绿联的5位硬盘盒实现简单的网盘功能,然而,还是觉的不太理想,比如使用filebrowser虽然可以备份文件和图片,当使用手机使用网页…...
C# dynamic 类型详解
简介 C# 中的 dynamic 是一种特殊类型,它允许在运行时确定对象的类型和成员,而不是在编译时。 dynamic 的定义 dynamic 是一种类型,它告诉编译器对其进行“动态类型解析”。 dynamic 类型的变量会跳过编译时类型检查,所有的操作…...
postgresql ERROR: cannot drop the currently open database
postgresql ERROR: cannot drop the currently open database 解释: 这个错误表明你正在尝试删除或者切换当前正在使用的数据库。在PostgreSQL中,一个数据库对应着一个进程,当一个数据库处于打开状态时,你不能直接删除或者切换它…...
Excel基础知识
一:数组 一行或者一列数据称为一维数组,多行多列称为二维数组,数组支持算术运算(如加减乘除等)。 行:{1,2,3,4} 数组中的每个值用逗号分隔列:{1;2;3;4} 数组中的每个值用分号分隔行列…...
【pwnlab_init靶场渗透】
文章目录 一、基础信息 二、信息收集 三、漏洞利用 四、反弹shell 五、提权 一、基础信息 Kali IP :192.168.20.146 靶机IP:192.168.20.157 二、信息收集 nmap -sS -sV -p- -A 192.168.20.157 开放了80、111、3306、50749等端口 访问一下80端口…...
【泰克生物】酶突变文库筛选技术:通过酵母展示实现酶的精准进化
酶工程是生物技术中的一个重要领域,涵盖了酶的改造、优化和应用。通过对酶分子进行定向进化,可以获得具有更高催化效率、更广泛底物特异性或更强稳定性的酶。酶突变文库筛选技术,尤其是酵母展示平台,提供了一种高效且可操作的方法…...
C++Primer 类简介
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
人工智能知识分享第三天-机器学习中交叉验证和网格搜索
交叉验证和网格搜索 交叉验证解释: 概述: 它是一种更加完善的, 可信度更高的模型预估方式, 思路是: 把数据集分成n份, 每次都取1份当做测试集, 其它的当做训练集, 然后计算模型的: 评分. 然后再用下1份当做测试集, 其它当做训练集, 计算模型评分, 分成几份, 就进行几次计算, 最…...
00序言:我为什么会选择AI?
序言:我为什么会选择AI? 2023年,对我来说是一个转折点。那一年,我在人工智能领域已经积累了几年的经验,深刻感受到了这场技术变革的巨大冲击。曾经,我也像许多人一样,怀疑自己是否能跟上这个快…...
【AIGC-ChatGPT副业提示词指令 - 动图】魔法咖啡馆:一个融合创意与治愈的互动体验设计
引言 在当今快节奏的生活中,咖啡早已不仅仅是提神醒脑的饮品,更成为了一种情感寄托和生活态度的表达。本文将介绍一个独特的"魔法咖啡馆"互动体验设计,通过将咖啡与情感、魔法元素相结合,创造出一个充满想象力和治愈感…...
VSCode outline显示异常的解决方法——清除VSCode的配置和用户文件
1. 删除所有配置文件 sudo apt remove --purge code2. 删除所有用户文件 rm -rf ~/.config/Code rm -rf ~/.vscode rm -rf ~/.local/share/code rm -rf ~/.cache/Code3. 重装Code sudo dpkg -i code_1.96.2-1734607745_amd64.deb如此,可修复异常导致的outline无…...
Maple软件的安装和使用
文章目录 1.前言说明2.我为什么要学习Maple3.软件的安装4.如何使用4.1基本的赋值语句4.2函数的定义4.3三个类型的书写介质 5.指数运算5.1使用面板5.2自己输入 6.对数的使用 1.前言说明 众所周知,我虽然是一名这个计算机专业的学生,但是我对于数学&#…...
elasticsearch-java客户端jar包中各模块的应用梳理
最近使用elasticsearch-java客户端实现对elasticsearch服务的Api请求,现对elasticsearch-java客户端jar包中各模块的应用做个梳理。主要是对co.elastic.clients.elasticsearch路径下的各子包的简单说明。使用的版本为:co.elastic.clients:elasticsearch-…...
android13 系统文字大小和显示大小的修改
没啥可解释,如题所示,修改系统默认文字大小和显示大小 一修改系统文字大小: 系统文字太小,需要修改文字大小修改如下 commit 82675b7d8ac278e80d94e6b2b1417b266065d2ec Author: admin <bianjbflyscale.cn> Date: Sat …...
【华为OD-E卷 - 任务总执行时长 100分(python、java、c++、js、c)】
【华为OD-E卷 - 任务总执行时长 100分(python、java、c、js、c)】 题目 任务编排服务负责对任务进行组合调度。 参与编排的任务有两种类型,其中一种执行时长为taskA,另一种执行时长为taskB。 任务一旦开始执行不能被打断&#x…...
vue中子组件给父组件传值
在 Vue.js 中,子组件向父组件传递数据或事件通常是通过 $emit 方法来实现的。这个方法允许子组件触发一个自定义事件,父组件可以通过监听这些事件来接收信息。以下是实现这一过程的基本步骤: 1. 子组件触发事件 在子组件中,使用…...
【js】记录预览pdf文件
接口调用拿到pdf的文件流,用blob处理这个文件流拿到url,使用window.open跳转新的窗口进行预览 api({dataType: blob, }).then(res >{if(res.code 0){this.previewPDF(res,application/pdf;charsetutf-8,pdf文件名)} })previewPDF (res, type, fname…...
【Spring MVC 异常处理机制】应对意外情况
在 Web 应用中,异常是不可避免的。用户的输入不合法,服务的某部分出错,或者数据库连接失败,这些情况都可能触发异常。那么问题来了:如何优雅地捕获并处理这些异常,让用户体验不至于因为一时的错误而受损&am…...
《计算机组成及汇编语言原理》阅读笔记:p128-p132
《计算机组成及汇编语言原理》学习第 10 天,p128-p132 总结,总计 5 页。 一、技术总结 1.8088 organization and architecture 8088处理器是16位电脑,寄存器是16位,数据总线(data bus)是8位,地址总线是20位。 (1)g…...
留学生交流互动系统|Java|SSM|VUE| 前后端分离
【技术栈】 1⃣️:架构: B/S、MVC 2⃣️:系统环境:Windowsh/Mac 3⃣️:开发环境:IDEA、JDK1.8、Maven、Mysql5.7 4⃣️:技术栈:Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…...
Windows IPC
进程间通信 (IPC,Inter-Process Communication) 进程间通信 (IPC) 是一种在进程之间建立连接的机制,在两台计算机或一台多任务计算机上运行,以允许数据在这些进程之间流动。进程间通信 (IPC) 机制通常用于客户端/服务器环境,并在…...
BMS存储模块的设计
目的 电池管理系统中存在着数据本地存储的要求,保证控制器重新上电后能够根据存储器中的一些参数恢复控制状态,和信息的下电存储1.继电器故障信息的存储。2. 系统性故障的存储。3.SOC、SOH相关信息的存储。4.均衡参数的存储。5.系统时间信息。6.出厂信息…...
2024-12-29-sklearn学习(25)无监督学习-神经网络模型(无监督) 烟笼寒水月笼沙,夜泊秦淮近酒家。
文章目录 sklearn学习(25) 无监督学习-神经网络模型(无监督)25.1 限制波尔兹曼机25.1.1 图形模型和参数化25.1.2 伯努利限制玻尔兹曼机25.1.3 随机最大似然学习 sklearn学习(25) 无监督学习-神经网络模型(无监督) 文章参考网站&a…...
【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
欢迎拜访:羑悻的小杀马特.-CSDN博客 本篇主题:带你众人皆知的约瑟夫环问题 制作日期:2024.12.29 隶属专栏:C/C题海汇总 目录 引言: 一约瑟夫环问题介绍: 11问题介绍: 1.2起源与历史背景&…...
【Elasticsearch】DSL查询文档
目录 1.DSL查询文档 1.1.DSL查询分类 1.2.全文检索查询 1.2.1.使用场景 1.2.2.基本语法 1.2.3.示例 1.2.4.总结 1.3.精准查询 1.3.1.term查询 1.3.2.range查询 1.3.3.总结 1.4.地理坐标查询 1.4.1.矩形范围查询 1.4.2.附近查询 1.5.复合查询 1.5.1.相关性算分 …...
MySQL第三弹----函数
笔上得来终觉浅,绝知此事要躬行 🔥 个人主页:星云爱编程 🔥 所属专栏:MySQL 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 一、合计/统计函数 1.1count…...
路由器刷机TP-Link tp-link-WDR5660 路由器升级宽带速度
何在路由器上设置代理服务器? 如何在路由器上设置代理服务器? 让所有连接到该路由器的设备都能够享受代理服务器的好处是一个不错的选择,特别是当需要访问特定的网站或加速网络连接的时候。下面是一些您可以跟随的步骤,使用路由器…...
Qml 中实现水印工具
【写在前面】 在 Qt 的 Quick 模块中,QQuickPaintedItem 是一个非常有用的类,它允许我们在 Qml 中自定义绘制逻辑。 我们可以通过这种方式实现水印工具,包括在文本、图片或整个窗口上添加水印。 本文将介绍如何在 Qml 中实现一个简单但功能…...
2024年数字政府服务能力优秀创新案例汇编(附下载)
12月19日,由中国电子信息产业发展研究院指导、中国软件评测中心主办的“2024数字政府评估大会”在北京召开,大会主题是:为公众带来更好服务体验。 会上,中国软件评测中心副主任吴志刚发布了2024年数字政府服务能力评估结果&#…...
数据链路层知识要点
这里写目录标题 数据链路层的功能1.封装成帧2.差错控制2.1循环冗余校验(CRC)2.2奇偶校验法 3.可靠传输3.1停止等待协议(SW)3.2后退N帧协议(GBN)3.3选择重传协议(SR) 4.使用广播信道的数据链路层5.以太网(局域网)5.1以太网与网卡5.2以太网的MAC地址 6.VLA…...
Linux实验报告6-用户管理
目录 一:实验目的 二:实验内容 (1)查看 Linux 系统的相关文件,回答以下问题 ①root 用户的 UID为多少?他的主目录在哪里? ②请举出一个普通用户,指出他的主目录及其所使用的 shell 是什么? (2)新建用户abc1(abc代表你的姓名拼音字母,下同),为其…...
微信小程序打印生产环境日志
微信小程序打印生产环境日志 新建一个log.js文件,写入以下代码: let log wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : nullmodule.exports {debug() {if (!log) returnlog.debug.apply(log, arguments)},info() {if (!log) returnlog.i…...
Edge如何获得纯净的启动界面
启动Edge会出现快速链接,推广链接,网站导航,显示小组件,显示信息提要,背景 ●复杂页面 ●精简页面 点击页面设置按钮 关闭快速链接 关闭网站导航 关闭小组件 关闭信息提要 关闭背景 关闭天气提示 精简页面看起来十分舒…...
探索开源项目 kernel:技术的基石与无限可能
在开源的广袤世界中,有一颗璀璨的明星——kernel(https://gitee.com/openeuler/kernel),它宛如一座技术的宝藏,蕴含着无数的智慧与创新,为众多开发者所瞩目和敬仰。 一、初窥 kernel 项目 当我第一次接触…...
使用PHP函数 “setcookie“ 设置cookie
在网站开发中,cookie是一种非常常用的技术,它用于在用户的浏览器中存储少量的数据,以便在不同页面之间传递信息。PHP提供了一个名为 "setcookie" 的函数,用于设置cookie的值和属性。在本文中,我们将学习如何…...
LUA基础语法
目录 变量篇 算数运算符 条件分支语句与循环语句 函数 表 Table 全局变量与本地变量 协程 元表 面向对象(封装,继承,多态) 常用自带库 垃圾回收 变量篇 print("hello") print("lua") --注释 --[[…...
链路聚合
链路聚合 目的:备份链路以及提高链路带宽。 链路聚合技术(Eth-Trunk):将多个物理接口捆绑成一个逻辑接口,将N条物理链路逻辑上聚合为一条逻辑链路。 正常情况下,想要配置链路聚合 1、A设备通过多条链路连接…...
OpenCV-Python实战(4)——图像处理基础知识
一、坐标 在 OpenCV 中图像左上角坐标为(0,0),竖直向下为 Y(height) ;水平向右为 X(width)。 二、生成图像 2.1 灰度图像 img np.zeros((h,w), dtype np.uint8) i…...
爬虫案例-爬取网页图片
爬虫案例-爬取网页图片 1、安装依赖库2、爬取图片的代码3、效果图 1、安装依赖库 #以下是安装http请求的第三方库 pip install requests urllib3 #以下是安装处理图片的第三方库 pip install image pillow #以下是安装python解析html的第三方库 pip install beautifulsoup4 …...
KAN网络最新优化改进——基于小波变换的KAN网络
KAN网络概念 KAN网络(Kolmogorov-Arnold Networks)是一种革命性的神经网络架构,源于Kolmogorov-Arnold表示定理。 该定理表明,多变量连续函数可通过有限数量的单变量连续函数的嵌套加法表示 。KAN的核心创新在于将传统神经网络中的固定激活函数替换为可学习的单变量函数,…...
【潜意识Java】深入理解Java中的方法重写,理解重写的意义,知道其使用场景,以及重写的访问权限限制等的完整笔记详细总结。
目录 一、方法重写是啥玩意儿 (一)定义和概念 (二)为啥要方法重写 二、方法重写的规则 (一)方法签名必须相同 (二)返回类型的要求 (三)访问权限的限制…...