文章目录
- 入门案例
- JDBC
- Mybatis
- Mybatis
- Mybatis介绍
- Mybatis的环境搭建
- 动态代理
- 增删改查示例
- 事务
- Mybatis的配置
- properties
- settings
- typeAliases
- environments
- mappers
- 输入映射
- 一个参数
- 多个参数
- 按位置传值
- 对象传值
- 使用Map进行传值
- #{}和${}的区别
- 输出映射
- 一个参数
- 多个参数
- 单个对象
- 多个对象
- resultMap
入门案例
JDBC
public class UserDaoImpl implements UserDao{
@Override
public User selectByPrimaryKey(Integer id) throws Exception {
// 1.获得连接,如果后面需要提交事务,则执行connection.commit
Connection connection = JdbcUtil.getConnection();
// 2.预编译,预编译过程中传入了SQL语句
PreparedStatement preparedStatement = connection
.prepareStatement("select id, username, password, age, birthday
, create_date, mobile from cskaoyan_user where id = ?");
// 3.提供占位符位置的值
preparedStatement.setInt(1,id);
// 4.执行查询获得结果集
ResultSet resultSet = preparedStatement.executeQuery();
// 5.创建一个接收结果集中的值的实例
User user = new User();
while (resultSet.next()) {
// 6.获得结果集中的username列(column)中的值
String username = resultSet.getString("username");
// 获得结果集中的password列(column)中的值
String password = resultSet.getString("password");
int age = resultSet.getInt("age");
Date birthday = resultSet.getDate("birthday");
Date createDate = resultSet.getDate("create_date");
String mobile = resultSet.getString("mobile");
user.setId(id);
// 7.通过set方法封装给user实例中的username这个成员变量(property)
user.setUsername(username);
// 通过set方法封装给user实例中的password这个成员变量(property)
user.setPassword(password);
user.setAge(age);
user.setBirthday(birthday);
user.setCreateDate(createDate);
user.setMobile(mobile);
}
return user;
}
}
//定义了UserDao接口,我们传入id,可以查询user的记录出来
public interface UserDao {
User selectByPrimaryKey(Integer id) throws Exception;
}
// 假如我们定义了实现类,那么我们可以这样子来调用获得user记录
public class JdbcExecution {
// 查询id为2的用户
public static void main(String[] args) throws Exception{
UserDao userDao = new UserDaoImpl();
User user = userDao.selectByPrimaryKey(2);
System.out.println("user = " + user);
}
}
这个过程比较繁琐,并且存在着很多定制化的内容和耦合
- SQL语句和代码直接耦合在一起
- 设置参数过程比较繁琐,对应的关系只有占位符的序号,如果有多个占位符
?
的话,容易出错 - 查询结果集的使用比较繁琐
- 手动调用构造方法来获得实例
- 要关注列名从结果集中取出数据
- 要关注列的类型手动调用不同的方法,比如
getInt
、getString
、getDate
- 取出的值需要使用
set
方法来封装
Mybatis
- 导包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
- 配置一个Mybatis的主配置文件,用来获取
SqlSessionFactory
<?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>
<!--添加日志的配置-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--环境配置,其实就是去配置数据库的连接-->
<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/test_20240301?characterEncoding=utf8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--读取映射文件-->
<mapper resource="com/coo1heisenberg/dao/UserMapper.xml"/>
</mappers>
</configuration>
- 配置一个专门用来存放SQL语句的配置文件
Mapper.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="userSql">
<!--namespace:命名空间-->
<!--Sql语句在映射文件中集中管理:是将SQL和代码做解耦
不同功能的SQL可以写在不同的映射文件里
比如处理test_user表相关的业务SQL可以放在UserMapper.xml里
-->
<!--这条sql语句的编号:命名空间 + 当前这个标签的id-->
<!--如果做查询,要写resultType,要写封装实例的全限定类名-->
<!-- 每个标签都需要一个唯一的id属性:
每一个标签的id不能重复(本Mapper文件中), 用来标识一条SQL -->
<!-- 在这个Mapper文件中, 怎么唯一表示SQL语句?
namespace.id (命名空间.标签的id ) 是这个SQL语句的坐标 -->
<!-- <insert> 插入标签 -->
<!-- <delete> 删除标签 -->
<!-- <update> 修改标签 -->
<!-- <select> 查询标签 -->
<!-- parameterType:参数的类型(可以省略,标准语法要指明 ) -->
<!-- resultType:返回的结果集的类型(不能省略) -->
<select id="selectById" resultType="com.coo1heisenberg.bean.User">
select * from account where id = #{id}
</select>
<!--Mybatis中的占位符是:#{内容},不是?-->
</mapper>
- 实现
@Data
public class User {
Integer id;
String name;
Integer money;
}
public interface UserDao {
public User selectUserById(Integer id);
}
/**
* SqlSessionFactory:每一个Mybatis应用都是以SqlSessionFactory的实例对象为核心的。
* 使用Mybatis必须以SqlSessionFactory的实例为核心,再以SqlSessionFactory的实例生产SqlSession实例对象的。
*
* SqlSession:这个其实表示和数据库之间的一个连接,里面封装了 Connection对象
*/
public class UserImpl implements UserDao{
@Override
public User selectUserById(Integer id){
// 在映射文件中的编号:usersql.selectById
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
User user = null;
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
// sql 会话,其实是对connection做了封装
SqlSession sqlSession = sqlSessionFactory.openSession();
// preparedStatement + setInt(1, id) + preparedStatement.executeQuery()
// 然后将resultSet变成一个User实例
user = sqlSession.selectOne("userSql.selectById", id);
} catch (IOException e) {
e.printStackTrace();
}
return user;
}
}
在上面的案例中MyBatis做了什么事情:
connection.preparedStatement
需要传入的Sql语句,我们仅仅提供了坐标(映射文件的命名空间+id)
- 参数和占位符的对应关系,自动对应起来
- resultSet获得结果集,并且封装为User实例的过程完全是MyBatis自动完成的
Mybatis
Mybatis介绍
- Mybatis是一个基于Java的持久层框架
- Mybatis是一个ORM(Object Relationship Mapping)框架(对象关系映射框架)
- Mybatis就是一个可以帮助我们把关系型数据库中的记录转化为Java对象,把Java对象转化为关系型数据库中的记录的这么一个框架。
- 类和表之间的关系(eg:User类和test_user表之间的关系)
- 类中的成员变量和表中的列之间的关系(名称、JavaType和JdbcType)
- 数据库中的一条记录和Java中的一个实例(比如一个user对象和test_user中的一条记录)
- Mybatis就是一个可以帮助我们把关系型数据库中的记录转化为Java对象,把Java对象转化为关系型数据库中的记录的这么一个框架。
- 它支持自定义 SQL、
存储过程以及高级映射- Mybatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
- Mybatis 可以通过简单的XML或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
- Mybatis就是一个可以帮助我们在Java代码中更加高效的去操作数据库的一个框架
Mybatis的环境搭建
- 导包在
pom.xml
中
<dependencies>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- 数据库驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 测试包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
- 配置MyBatis的主配置文件(
mybatis-config.xml
)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://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/xxx?useSSL=false&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 去查找的Mapper文件 -->
<mappers>
<mapper resource="com/snow/www/mapper/AccountMapper.xml"/>
</mappers>
</configuration>
- 创建一个Java接口Mapper接口文件 (注意路径)
- 创建一个与Java接口文件对应的
Mapper.xml
配置文件
之后的步骤见上面的Mybatis的入门案例
动态代理
上面代码存在的一些不足:
- 目前Mybatis使用起来还不够灵活,不够简单。
- 虽然解决了SQL语句硬编码的问题,但是又出现了新的问题,SQL语句的坐标存在硬编码
sqlSession
调用的方法需要我们自己去指定,也就是UserDaoImpl
中的内容还不够通用,我们想要进一步干掉它
而Mybatis的动态代理可以帮助我们去生成接口的代理对象,我们可以自己不实现接口。
eg:
public class MyBatisUtil {
// 线程安全的值,可以全局共享
private static SqlSessionFactory sqlSessionFactory;
static {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().
build(Resources.getResourceAsStream("mybatis.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
}
public class MybatisTest {
@Test
public void myTest() {
// Mybatis生成的代理对象 -> 没有委托类 -> 只能从接口身上获得一些信息
/**
* 获得接口的全限定类名
* 获得方法的数组 -> 方法的名称、返回值类型、参数的个数和类型
* 需要一个sql语句在映射文件中的坐标 -> 能否从上面选择一些信息保证组合起来的坐标是唯一的
* 坐标 = 接口的权限定类名 + 方法名(接口中的方法不允许重载)
*/
SqlSessionFactory sqlSessionFactory = MyBatisUtil.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.selectUserById(2);
System.out.println(user);
}
}
<?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="com.coo1heisenberg.dao.UserDao">
<!--namespace:命名空间-->
<!--Sql语句在映射文件中集中管理:是将SQL和代码做解耦
不同功能的SQL可以写在不同的映射文件里
比如处理test_user表相关的业务SQL可以放在UserMapper.xml里
-->
<!--这条sql语句的编号:命名空间 + 当前这个标签的id-->
<!--如果做查询,要写resultType,要写封装实例的全限定类名-->
<!-- 每个标签都需要一个唯一的id属性:
每一个标签的id不能重复(本Mapper文件中), 用来标识一条SQL -->
<!-- 在这个Mapper文件中, 怎么唯一表示SQL语句?
namespace.id (命名空间.标签的id ) 是这个SQL语句的坐标 -->
<!-- <insert> 插入标签 -->
<!-- <delete> 删除标签 -->
<!-- <update> 修改标签 -->
<!-- <select> 查询标签 -->
<!-- parameterType:参数的类型(可以省略,标准语法要指明 ) -->
<!-- resultType:返回的结果集的类型(不能省略) -->
<select id="selectUserById" resultType="com.coo1heisenberg.bean.User">
/*不建议写select* */
select id,name,money from account where id = #{id}
</select>
<!--Mybatis中的占位符是:#{内容},不是?-->
</mapper>
增删改查示例
<!--增删改-->
<!--insert、delete、update标签 id属性 对应的接口中的方法返回值都可以写int-->
<insert id="insertUser">
insert into account(id, name, money) values (#{id}, #{name}, #{money});
</insert>
<update id="updateUser">
update account set name = #{name} where id = #{id};
</update>
<delete id="deleteById">
delete from account where id = #{id};
</delete>
对应接口:
int insertUser(User user);
int updateUser(String name, Integer id);
int deleteById(Integer id);
但是存在问题:Mybatis中openSession不提供事务的提交
事务
在使用Mybatis的时候, 自带事务,而且事务默认情况下是不会自动提交的
- 解决方法一:执行完SQL语句之后, 使用
sqlSession
提交事务
eg:sqlSession.commit();
- 解决办法二: 执行完SQL语句之后, 使用
sqlSession
内部封装的Connection
提交事务
eg:Connection conn = sqlSession.getConnection(); conn.commit();
- 解决办法三(自动提交) :在获得
SqlSession
的时候,给sqlSessionFactory.openSession
设置为真
eg:SqlSession session = sqlSessionFactory.openSession(true);
Mybatis的配置
Mybatis的核心配置文件:
(这些标签都是有序的,按下面排序)
properties
properties表示可以外部配置的属性,并可以进行动态替换。(作为典型的是JDBC配置)
eg:
jdbc.properties文件中:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_20240301?useSSL=false&userUnicode=true&characterEncoding=utf8
username=root
password=123456
在Mybatis_config.xml中的内容为:
<configuration>
<!-- 引入外部配置文件 -->
<properties resource="jdbc.properties" ></properties>
</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="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
settings
settings是MyBatis的行为配置(类似于idea和settings的关系)
eg:
日志的配置:
<configuration>
<settings>
<!-- 添加日志的配置,能够在控制台输出日志的 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
其它一些settings配置:
<settings>
// 缓存
<setting name="cacheEnabled" value="true"/>
// 懒加载
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="safeResultHandlerEnabled" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
<setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver"/>
<setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/>
<setting name="callSettersOnNulls" value="false"/>
<setting name="returnInstanceForEmptyRow" value="false"/>
<setting name="logPrefix" value="exampleLogPreFix_"/>
<setting name="logImpl" value="SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING"/>
<setting name="proxyFactory" value="CGLIB | JAVASSIST"/>
<setting name="vfsImpl" value="org.mybatis.example.YourselfVfsImpl"/>
<setting name="useActualParamName" value="true"/>
<setting name="configurationFactory" value="org.mybatis.example.ConfigurationFactory"/>
</settings>
typeAliases
typeAlies类型别名。(也就是我们可以对 类 起别名,简化操作) (暂时不建议使用)
eg:
<configuration>
<!-- 类型别名 -->
<typeAliases>
<!-- alias别名 type全限定名 -->
<typeAlias alias="account" type="com.snow.www.bean.Account"/>
<typeAlias alias="user" type="com.snow.www.bean.User"/>
</typeAliases>
</configuration>
则在Mapper.xml中的使用为:
// account == com.snow.www.bean.Account
<select id="selectAccountById" resultType="account">
select * from account where id = #{id}
</select>
environments
environments:可以配置成适应多种环境。比如开发环境、测试环境和生产环境等可能需要有不同的配置。
eg:
<!-- 环境的配置,其实就是去配置数据库连接-->
<environments default="development">
<!-- 环境的id,是唯一的-->
<environment id="development">
<!-- 事务管理器
JDBC: 使用JDBC连接来管理事务
MANAGED: 把事务的管理交给外部的容器 -->
<!-- 如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,
因为 Spring 模块会使用自带的管理器来覆盖前面的配置。-->
<transactionManager type="JDBC"/>
<!--
POOLED: 使用Mybatis自带的连接池
UNPOOLED:不使用连接池
JNDI:使用外部的连接池 -->
<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>
mappers
这个是映射器的配置。配置mapper.xml
配置文件。
- 配置方式一:直接以对应mapper文件的相对路径
eg:
<configuration>
<mappers>
<mapper resource="com/snow/www/mapper/User.xml"/>
<mapper url="file:///D:\javaee\....">
<mapper class="com.coo1heisenberg.dao.UserDao">
</mappers>
</configuration>
- 配置方式二:配置某个包下的所有的配置文件
eg:
<configuration>
<!--
1. 接口和映射文件编译后要在同一级目录,并且同名
2. 接口的全限定类名作为映射文件的命名空间
3. 接口中的方法名(方法不允许重载)作为映射文件中的标签id(标签id不允许重复)
-->
<mappers>
<package name="com.snow.www.mapper"/>
</mappers>
</configuration>
输入映射
- 输入映射其实就是在说Mybatis是如何传值的
- 映射文件中的SQL语句中的语法:
#{}
里写什么东西,#{}
这个位置最终在预编译的过程中变为了?
- 在Mapper接口中,方法的形参写了什么样式(个数、类型、注解),最终在映射文件中该方法对应的sql语句中的
#{}
应该如何写
一个参数
一个参数:(基本类型、包装类、String)
#{任意值}
来取值: 不建议使用(显得不标准),建议使用注解写法- 虽然一个参数的时候, 可以在
{}
内部任意书写参数名, 这种乱写行为不好, 不要这么写
- 虽然一个参数的时候, 可以在
eg:
<select id="selectAccountById" resultType="account">
select * from account where id = #{xxx}
</select>
- 如果在方法中 的一个参数加了
@Param
注解,那么 后面就只能通过#{注解值}
来取值
eg:
// 查找
public Account selectAccountById2(@Param("id") Integer id);
<select id="selectAccountById2" resultType="acc">
select * from account where id = #{id}
</select>
多个参数
多个参数:需要注解指明#{注解值}
来取值
-
- 直接写多个值,用参数名简单匹配是不识别的
-
- 如果参数名简单匹配是不识别,又不想加注解,也是有别的解决手段(按位传值: 不建议), 但是建议加注解(最标准的写法)
eg:
List<Account> selectListByIdOrName(@Param("id") Integer id,@Param("name") String name);
<select id="selectListByIdOrName" resultType="acc">
select * from account where id = #{id} or name = #{name}
</select>
按位置传值
按位传值:完全不建议(容易因为程序员的记忆和修改导致bug产生, 除非除了按位传值没办法了)
- 方式一::
arg0、arg1、arg2...
- 下标从0开始
- 方式二:
param1、param2、param3...
- 下标从1开始
eg:
userMapper.insertUser("zs", 18, "beijing");
方式一:
<insert id="insertUser">
insert into `user` set `name`=#{arg0}, age=#{arg1}, address=#{arg2}
</insert>
方式二:
<insert id="insertUser">
insert into `user` set `name`=#{param1}, age=#{param2}, address=#{param3}
</insert>
对象传值
- 方式一:SQL使用的参数命名要和对象内部属性保持一致 (
#{成员变量名}
来取值)
eg:
// 对象传值,没有使用@Param注解,则是成员变量名
int insert1(User user);
<insert id="insert1">
insert into account(id,name,money) values (#{id}, #{name} ,#{money})
</insert>
- 方式二:对象有注解,必须通过
#{注解值.成员变量名}
来取值
eg:
// 对象传值,使用@Param注解,则是@Param写了什么就用什么
// user.money....
int insert2(@Param("user") User user);
<insert id="insert2">
insert into account(id,name,money) values (#{user.id}, #{user.name}, #{user.money})
</insert>
使用Map进行传值
- 方式一:SQL使用的参数命名要和Map中存储数据的key保持一致 (
#{key}
来取值)
eg:
// Map map = new HashMap();
// map.put("id", 3);
// map.put("name", "ss")
// Map传值 --> 没有使用@Param注解 --> #{}里面写的是map的key:id和name
int updateNameById(Map map);
<update id="updateNameById">
update account set name = #{name} where id = #{id}
</update>
- 方式二:Map对象有注解, 必须通过
#{注解值.key}
来取值
eg:
// Map传值 --> 使用@Param注解 --> #{}里面写的是@Param注解的值 + map的key:map.id和map.name
int updateNameById2(@Param("map") Map map);
<update id="updateNameById2">
update account set name = #{map.name} where id = #{map.id}
</update>
小结:
输入映射,Mybatis如何使用的user,通过get方法来使用。
#{}和${}的区别
- 使用
${}
做的就是字符串的拼接,如果传入的是字符串,需要在${}
外围手动增加单引号``- 核心点:使用
${}
有SQL注入的风险(SQL注入指:在执行的SQL语句之外额外执行一部分,导致信息泄露或者数据库被丢弃)
- 核心点:使用
- 使用
#{}
过程是预编译,不会有SQL注入的风险 #{参数}
使用:预编译占位 (尽量使用#{}
) PreparedStatement
eg:
<insert id="insert1" >
insert into account(id,name,money) values (#{id}, #{name} ,#{money})
</insert>
/**
* ==> Preparing: insert into account(id,name,money) values (?, ? ,?)
* ==> Parameters: 6(Integer), ss(String), 8000(Integer)
* <== Updates: 1
*/
${参数}
使用:字符串拼接, Statement (存在SQL注入问题)- 一般用在排序或者把表名传入的时候
eg:
<insert id="insert3">
insert into account(id,name,money) values (${id}, `${name}` ,`${money}`)
</insert>
/**
* ==> Preparing: insert into account(id,name,money) values (5, `ws` ,`7000`)
*/
输出映射
- 输出映射一定和查询有关系,一定对应的是select标签
- 使用select标签一定使用和类型有关系的属性:
resultType
resultMap
resultType
中可以写别名
eg:
-- 只有1列,并且记录数为1条 → 查询user表中有多少条记录
-- 一个int或Integer类型的值来接收
select count(*) from account ;
-- 只有一列,结果的记录数为多条 → 查询年龄为xxx的用户的名称
-- 数组或List、Set
select name from account where age = 25;
-- 多列,结果的记录数为1条 → 查询id为某个值的用户的全部信息
-- 引用类型对象
select id,name,money from account where id = 2;
-- 多列,结果的记录数为多条 → 查询年龄为xxx的用户的全部信息
-- 引用类型对象的数组或List、Set
select id,name,money from account where age = 25 ;
综上可得:
- 选择何种封装类型:取决于结果集中的列的个数,以及结果的记录数
- 封装最终体现在:落脚点在Mapper接口中的方法的返回值类型
一个参数
指的是:结果列为1且记录数为1(或0)
- 一个参数: 必须要有resultType(写简单参数的
全限定名称
或者是内置的别名
)
eg:
// 单个列,结果记录数为1
int selectCount();
String selectNameById(Integer id);
<select id="selectCount" resultType="java.lang.Integer">
select count(*) from account;
</select>
<select id="selectNameById" resultType="java.lang.String">
select name from account where id = #{id};
</select>
多个参数
指的是:列只有一列,结果集中的记录数有多条(0或1条)
- 指: 多个参数构成的数组/List/Set
- 当我们返回多个简单参数的时候,在方法中定义的是数组就会返回数组,定义的是集合就会返回集合。
- xml中的标签配置不需要改变。并且, resultType的值是单个记录的类型
eg:
// 单个列,结果记录数为多条
// 按照不同的类型来封装,但是SQL语句是一样的
String[] selectNamesByMoney1(Integer money);
List<String> selectNamesByMoney2(Integer money);
Set<String> selectNamesByMoney3(Integer money);
<select id="selectNamesByMoney1" resultType="java.lang.String">
select name from account where money = #{money};
</select>
<select id="selectNamesByMoney2" resultType="java.lang.String">
select name from account where money = #{money};
</select>
<select id="selectNamesByMoney3" resultType="java.lang.String">
select name from account where money = #{money};
</select>
单个对象
- 核心点:查询结果集中的列名 要和 对象中的成员变量名(set方法)相同
- 查询结果集中的列名可以通过as起别名的方式做修改
eg:
User selectAllMember(Integer id);
User user = userMapper.selectAllMember(2);
<select id="selectAllMember" resultType="com.coo1heisenberg.bean.User">
select * from account where id = #{id};
</select>
多个对象
- 多个对象:数组/List/Set
- resultType的值是单个元素的类型
JDBC的封装举例:
ResultSet resultSet = prepareStatement.executeQuery();
List<User> users = new ArrayList<>();
while(resultSet.next()){
User user = new User();
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
users.add(user);
}
//如果你需要一个Set可以在第2行这里定义为一个set ,也可以将这个List转为一个Set
//如果你需要一个数组,也可以将这个List转为一个数组
eg:
// 多个列,结果记录数为多条
User[] selectByAge1(@Param("age") Integer age);
List<User> selectByAge2(@Param("age") Integer age);
Set<User> selectByAge3(@Param("age") Integer age);
<select id="selectByAge1" resultType="com.coo1heisenberg.demo2.bean.User">
select * from account
where age = #{age}
</select>
<select id="selectByAge2" resultType="com.coo1heisenberg.demo2.bean.User">
select * from account
where age = #{age}
</select>
<select id="selectByAge3" resultType="com.coo1heisenberg.demo2.bean.User">
select * from account
where age = #{age}
</select>
resultMap
- resultMap:是用来做参数映射的
- 存在这样的对应关系,我们才知道从结果集拿那一列的值(
resultSet.getString("列名")
),获得的值要封装给哪一个成员变量 - resultMap是可以复用的
eg:
UserVo selectUserVoByPrimaryKey(@Param("id") Integer id);
UserVo userVo = userMapper.selectUserVoByPrimaryKey(2);
System.out.println("userVo = " + userVo);
<!--id属性:是要和select标签中的resultMap属性建立联系-->
<!--type属性:写的是要封装的对象的全限定类名(或别名)-->
<resultMap id="userVoMap" type="com.coo1heisenberg.bean.UserVo">
<!--查询结果集中的列名要和成员变量名建立映射关系-->
<id property="id" column="id"></id>
<result property="money" column="money"></result>
<result property="name" column="name"></result>
</resultMap>
<!--resultMap属性中写的是引用的resultMap标签的id-->
<select id="selectUserVoByPrimaryKey" resultMap="userVoMap">
select * from account where id = #{id};
</select>