项目结构
表结构
users表
t_student表
UserMapper.java
package org.huse.mapper;
import org.huse.pojo.User;
import java.util.List;
/*接口式开发:方法的名称要和映射文件中的sql语句中的statmentId一致*/
publicinterfaceUserMapper{
public User findById(int id);
publicvoidaddUser(User user);
publicvoidupdateUser(User user);
publicvoiddeleteUser(int id);
}
Student.java
package org.huse.pojo;
publicclassStudent{
privateint id;
private String name;
privateint age;
@Override
public String toString(){
return"Student{" +
"id=" + id +
", name='" + name + ''' +
", age=" + age +
'}';
}
publicintgetId(){
return id;
}
publicvoidsetId(int id){
this.id = id;
}
public String getName(){
return name;
}
publicvoidsetName(String name){
this.name = name;
}
publicintgetAge(){
return age;
}
publicvoidsetAge(int age){
this.age = age;
}
}
User.java
package org.huse.pojo;
publicclassUser{
private Integer uid;
//private String uname;
//驼峰命名
private String userName;
private Integer uage;
@Override
public String toString(){
return"User{" +
"uid=" + uid +
", userName='" + userName + ''' +
", uage=" + uage +
'}';
}
public Integer getUid(){
return uid;
}
publicvoidsetUid(Integer uid){
this.uid = uid;
}
public String getUserName(){
return userName;
}
publicvoidsetUserName(String userName){
this.userName = userName;
}
public Integer getUage(){
return uage;
}
publicvoidsetUage(Integer uage){
this.uage = uage;
}
}
MybatisUtils.java
package org.huse.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
publicclassMybatisUtils{
privatestatic SqlSessionFactory sqlSessionFactory=null;
static {
//创建sqlsessionfactory
try {
InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
thrownew RuntimeException(e);
}
}
publicstatic SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
mapper标签:配置各类声明
namespace:名称空间,由于映射文件可能有多个,为了防止crud语句的唯一标识被重复,需要设置空间名称
-->
<mappernamespace="org.huse.mapper.StudentMapper">
<resultMapid="studentMap"type="student">
<idcolumn="sid"property="id"></id>
<resultcolumn="sname"property="name"></result>
<resultcolumn="sage"property="age"></result>
</resultMap>
<selectid="findAllStudent"resultMap="studentMap">
select * from t_student
</select>
</mapper>
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--类路径引入-->
<!--<mapper namespace="org.huse.pojo.User">-->
<!--接口引入-->
<mappernamespace="org.huse.mapper.UserMapper">
<!--
resultType="User" 表示这个查询的结果将会被映射到 User 类型的对象上。
确保所指定的类型与查询结果的结构相匹配是很重要的,这样可以正确地将数据库中的数据转换为应用程序中使用的对象。
-->
<!--id="findById"意味着你为这个特定的查询操作定义了一个名为findById的标识符。-->
<!--用sql元素-->
<!--/* 原sql语句select uid, user_name, uage from users where uid = #{id}*/-->
<sqlid="users">users</sql>
<sqlid="someinclude">
from <includerefid="users"></include>
</sql>
<sqlid="UserColumns">
uid,user_name,uage
</sql>
<selectid="findById"parameterType="int"resultType="user">
select <includerefid="UserColumns"></include>
<includerefid="someinclude"></include>
where uid=#{id}
</select>
<insertid="addUser"parameterType="user"useGeneratedKeys="true"keyProperty="uid">
INSERT into users(uid, user_name, uage) values (null,#{userName},#{uage})
</insert>
<!--主键回显,useGeneratedKeys="true" keyProperty="uid" 适用于主键自增情况-->
<!--<insert id="addUser" parameterType="user" useGeneratedKeys="true" keyProperty="uid"> INSERT into users(uid, user_name, uage) values (null,#{userName},#{uage}) </insert>-->
<!--适用于主键自增不自增状态-->
<!--<insert id="addUser" parameterType="user" > <selectKey keyProperty="uid" resultType="Integer" order="BEFORE"> /*下面这条语句表示查询插入后自增的主键值,支持主键自增,这个order是after*/
/*SELECT LAST_INSERT_ID()*/
<!–第二种不支持主键自增,因为他不会自增,所以order为BEFORE,RAND表示是一个随机数,并且这个时候uid改为id–>
SELECT FLOOR(RAND()*1000+1) </selectKey> INSERT into users(uid, user_name, uage) values (#{uid},#{userName},#{uage}) </insert>-->
<updateid="updateUser"parameterType="user">
UPDATE users set user_name=#{userName},uage=#{uage} where uid=#{uid}
</update>
<deleteid="deleteUser"parameterType="Integer">
DELETE FROM users where uid=#{uid}
</delete>
</mapper>
application.properties
账号密码数据库名用自己的
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.username=root
mysql.password=123456
mysql.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf-8&useUnicode=true&useSSL=false
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC"-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入外部文件 -->
<propertiesresource="application.properties"></properties>
<settings><!--开启全局缓存,默认是true-->
<settingname="cacheEnabled"value="true"/>
<!--开启全局懒加载,默认是false-->
<settingname="lazyLoadingEnabled"value="true"></setting>
<!--开启关联属性的懒加载,默认是false-->
<settingname="aggressiveLazyLoading"value="true"></setting>
<!--开启驼峰-->
<settingname="mapUnderscoreToCamelCase"value="true"></setting>
</settings>
<!--设置别名第一种方式-->
<!--<typeAliases> <typeAlias type="org.huse.pojo.User" alias="user"></typeAlias> </typeAliases>-->
<!--设置别名第二种方式,不区分大小写-->
<typeAliases>
<packagename="org.huse.pojo"/>
</typeAliases>
<!-- 数据源环境配置 -->
<environmentsdefault="development">
<environmentid="development">
<transactionManagertype="JDBC"/>
<dataSourcetype="POOLED">
<propertyname="driver"value="${mysql.driver}"/>
<propertyname="url"value="${mysql.url}"/>
<propertyname="username"value="${mysql.username}"/>
<propertyname="password"value="${mysql.password}"/>
</dataSource></environment></environments>
<mappers><!--配置UserMapper.xml文件的位置-->
<mapperresource="org/huse/mapper/UserMapper.xml"/>
<!--第三种配置:配置接口的全路径
此处mapper配置目的::将mapper.xml映射文件交给mybatis
mapper映射文件路径=位置+映射文件名
则需要满足规范
1、映射文件的位置必须放在接口的同包目录下
2、映射文件名必须和接口名相同
-->
<!--<mapper class="org.huse.mapper.UserMapper"/>--><!--第四种配置方式,如果有很多映射文件,第三种就不太适用了,于是我们用包名引入-->
<!--<package name="org.huse.mapper"/>-->
<mapperresource="org/huse/mapper/StudentMapper.xml"></mapper>
</mappers>
</configuration>
MyBatisTest.java
package org.huse.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.huse.pojo.Student;
import org.huse.utils.MybatisUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
publicclassMyBatisTest{
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
@Before/*用来给上面sql两个对象进行初始化*/
publicvoidinit(){
sqlSession = MybatisUtils.getSession();
}
@Test
publicvoidfindAllStudentTest(){
List<Student> studentList=sqlSession.selectList("org.huse.mapper.StudentMapper.findAllStudent");
for(Student s:studentList){
System.out.println(s);
}
}
@After
publicvoiddestory(){
sqlSession.commit();
sqlSession.close();
}
}
UserTest.java
package org.huse.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.huse.pojo.User;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
publicclassUserTest{
@Test
publicvoidfindById()throws IOException {
// 1.读mybatis核心配置文件
InputStream rs = Resources.getResourceAsStream("mybatis-config.xml");
// 2.创建sqlSessionFactoryBuilder对象来构建工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(rs);
// 3.通过工厂对象来创建sqlSession对象操作数据库
SqlSession sqlSession = build.openSession();
// 4.执行查询操作,主要statementId的值
User user = sqlSession.selectOne("org.huse.mapper.UserMapper.findById", 1);
System.out.println(user);
// 关闭事务,将数据源连接还给连接池
sqlSession.close();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<projectxmlns="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>org.example</groupId>
<artifactId>mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<properties><maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies><!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!--单元测试,JUnit 是一个用于测试 Java 代码的工具。它帮助你检查你的程序是否按预期工作-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
<scope>runtime</scope>
</dependency></dependencies>
</project>
resulttype和resultmap的区别
resultType
和 resultMap
是 MyBatis 中用于定义查询结果如何映射到 Java 对象的两种不同方式。它们各自有其特定的用途和优势。
resultType
-
用途:当数据库查询的结果可以直接映射到一个简单的 Java 对象(POJO)时使用。 -
工作原理:MyBatis 会自动将查询结果集中的每一行数据按照列名(或别名)与目标对象的属性名进行匹配,并执行相应的类型转换后填充对象。 -
适用场景: -
数据库表结构与实体类结构非常相似或一致。 -
不需要复杂的映射逻辑,如嵌套对象、集合等。 -
优点:简单易用,适合快速开发和简单的映射需求。 -
示例: <selectid="selectUsers"resultType="org.huse.pojo.User">
SELECT uid, user_name, uage FROM users
</select>
resultMap
-
用途:用于更复杂的数据映射场景,特别是当数据库表结构与Java对象不完全对应时。
-
工作原理:通过在XML配置文件中显式定义结果映射关系,可以实现对查询结果的精确控制,包括处理不同的列名、类型转换、关联关系(一对一、一对多)、嵌套对象等。
-
适用场景:
-
需要处理复杂的映射关系,例如联合查询返回多个表的数据。 -
当数据库字段名与Java对象属性名不匹配时。 -
处理继承或多态性。 -
映射到嵌套对象或集合。 -
优点:提供了极大的灵活性和控制力,能够处理几乎任何类型的映射需求。
-
示例:
<resultMapid="userResultMap"type="org.huse.pojo.User">
<idproperty="uid"column="uid"/>
<resultproperty="userName"column="user_name"/>
<resultproperty="uage"column="uage"/>
</resultMap>
<selectid="selectUsers"resultMap="userResultMap">
SELECT uid, user_name, uage FROM users
</select>
总结
-
选择依据:如果您的查询结果可以直接映射到Java对象且无需额外处理,则使用 resultType
即可;若涉及到复杂的映射关系或者需要对结果进行特殊处理,则应使用resultMap
。 -
性能考虑:一般来说,使用 resultType
可能会稍微快一些,因为它不需要解析额外的映射配置,但在大多数情况下这种差异可以忽略不计。更重要的是根据实际需求选择合适的方式来保证代码的可读性和维护性。
resultmap标签
在MyBatis的<resultMap>
配置中,使用<id>
和<result>
标签的主要区别在于它们所标识的数据字段的作用以及MyBatis如何利用这些信息来优化对象的映射和数据库操作。
<id>
标签
-
用途:用于指定结果集中作为主键的列。这有助于MyBatis更高效地管理缓存、识别对象等。
-
功能:
在您的例子中,
sid
被标记为<id>
,意味着它代表了学生表中的主键。这样做可以确保MyBatis能够正确地识别每个学生对象,并且在进行后续的更新或删除操作时能够准确地定位到对应的数据库记录。 -
帮助MyBatis确定对象的身份(identity),这对于更新和删除操作特别有用,因为MyBatis需要知道哪个实例是相同的记录。 -
提升MyBatis内部缓存机制的效果,因为它能更好地识别相同对象的不同实例。
<result>
标签
-
用途:用于映射除主键之外的其他普通列到Java对象的属性上。
-
功能:
-
普通数据成员的映射,不涉及对象身份的识别。 -
可以处理各种类型的数据转换,从数据库列值到Java类型的自动转换。
在Java中,InputStream
和 Reader
是用于处理输入数据的两个不同基类,它们分别处理字节流和字符流。了解它们之间的差异对于正确选择合适的工具来读取文件或其他资源非常重要。
inputstream和reader的区别
InputStream(字节流)
-
用途: InputStream
类及其子类用于从各种来源(如文件、网络连接等)读取原始字节流。 -
适用场景:当你需要处理二进制数据或任何类型的原始字节时使用。例如,读取图像文件、音频文件或者任何非文本格式的数据。 -
编码问题:不直接处理字符编码问题,因为它操作的是字节而不是字符。如果要处理文本数据,通常需要手动指定字符集进行转换。 -
常见子类: -
FileInputStream
-
ByteArrayInputStream
-
BufferedInputStream
Reader(字符流)
-
用途: Reader
类及其子类用于读取字符流,即处理文本数据。它能够将字节流根据特定的字符编码转换为字符流。 -
适用场景:适用于读取文本数据,如文本文件、字符串等。使用 Reader
可以避免手动处理字符编码的问题,因为你可以指定字符集。 -
编码问题:支持字符编码,允许你指定如何解释字节序列作为字符。这对于处理包含非ASCII字符的文本文件特别重要。 -
常见子类: -
FileReader
-
StringReader
-
BufferedReader
主要差异
-
数据类型:
-
InputStream
处理字节(8位),适合所有类型的输入。 -
Reader
处理字符(通常是16位Unicode字符),专为文本数据设计。 -
编码支持:
-
InputStream
不提供字符编码转换功能。 -
Reader
提供了对字符编码的支持,可以方便地处理不同语言的文字。 -
性能与便利性:
-
对于纯文本数据,使用 Reader
更加方便,特别是当需要考虑字符编码时。 -
如果你需要处理非文本数据(如图片、视频等),则应使用 InputStream
。 -
应用场景:
-
使用 InputStream
来读取二进制文件或执行低级别的I/O操作。 -
使用 Reader
来读取文本文件或执行高级别的文本I/O操作。
在MyBatis中的应用
在MyBatis中,Resources.getResourceAsStream(String resource)
方法返回一个 InputStream
,而 Resources.getResourceAsReader(String resource)
返回一个 Reader
。两者都可以用来加载 MyBatis 的配置文件 (mybatis-config.xml
),但选择哪一个取决于你的具体需求:
-
如果您只是简单地加载并解析XML配置文件,并且不需要特别处理字符编码,那么使用 InputStream
就足够了。 -
如果您的配置文件可能包含非ASCII字符,并且您希望确保正确的字符编码处理,则使用 Reader
可能更为合适。
总的来说,选择 InputStream
还是 Reader
主要基于你要处理的数据类型以及是否需要考虑字符编码的问题。对于大多数文本文件的读取任务,推荐使用 Reader
因为其更易于处理字符编码。而对于二进制数据或无需关心字符编码的情况,InputStream
则是一个更好的选择。
静态初始块
静态初始化块的作用
-
执行一次性的静态初始化:
-
静态初始化块在类第一次被加载到JVM时自动执行,并且只会执行一次。 -
这非常适合用于初始化那些在整个应用程序生命周期内只需要设置一次的静态变量或资源。 -
处理复杂的初始化逻辑:
-
如果某些静态变量的初始化过程比较复杂,不适合直接在声明时进行赋值,可以将初始化逻辑放在静态初始化块中。 -
例如,从文件读取数据、网络请求获取配置信息等场景下,静态初始化块提供了一个合适的场所来执行这些操作。 -
确保初始化顺序:
-
Java保证静态初始化块会在任何静态变量被访问之前执行,这有助于确保所有依赖于这些静态变量的对象都能看到完全初始化后的状态。 -
当存在多个静态变量时,静态初始化块可以帮助控制它们之间的初始化顺序。 -
捕获异常并处理错误:
-
在静态初始化过程中如果可能发生异常(如I/O错误),可以在静态初始化块中捕获这些异常,并采取适当的措施(如记录日志、抛出运行时异常等)。
静态初始化块是一个强大的工具,特别适用于那些需要在类加载时一次性完成的初始化任务。它可以简化复杂的初始化逻辑,确保资源在首次使用前已经被正确初始化,并且提供了对初始化过程中可能出现的异常进行处理的能力。然而,需要注意的是,由于静态初始化块只执行一次,因此不适合用来初始化那些可能需要多次更新的状态或资源。此外,过度使用静态初始化块可能会导致难以调试的问题,因此应该谨慎使用
原文始发于微信公众号(安全泡泡鱼):Mybatis-UserMapper+StudentMapper
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论