IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> MyBatis【java进阶笔记六】 -> 正文阅读

[Java知识库]MyBatis【java进阶笔记六】

目录

JDBC

HiBernate

MyBatis

具体使用操作:

CRUD:

查询 Retrieve:

插入 Create:

更新 Update:

删除 Delete:

入参:

SQL 注入的问题:

结果集:

级联:

Association 一对一

Collection 一对多

缓存:

动态SQL

动态代理

JDK 动态代理

CGLIB字动态代理


JDBC

使用 JDBC 的 五个步骤

1> 注册驱动和数据库信息。

2> 获得Connection,并使用它打开Statement对象。

3> 通过Statement对象执行SQL语句,并获得结果对象ResultSet。

4> 通过代码将ResultSet对象转化为POJO对象。

5> 关闭数据库资源。

缺点:

1> 代码量很大,繁琐。

2> 需要我们对异常进行正确捕获并关闭链接。

具体使用操作:

① 添加依赖

 ? ? ? ?<!-- JDBC -->
 ? ? ? ?<dependency>
 ? ? ? ? ? ?<groupId>mysql</groupId>
 ? ? ? ? ? ?<artifactId>mysql-connector-java</artifactId>
 ? ? ? ? ? ?<version>5.1.48</version>
 ? ? ? ?</dependency>

② 代码实现(UserExecutor.java)

public class UserExecutor {
 ? ?public static void main(String[] args) throws Throwable {
 ? ? ? ?// 1> 注册驱动和数据库信息。
 ? ? ? ?//Class.forName("com.mysql.cj.jdbc.Driver");
 ? ? ? ?Class.forName("com.mysql.jdbc.Driver");
?
 ? ? ? ?// 2> 获得Connection,并使用它打开Statement对象。
 ? ? ? ?Connection connection = null;
 ? ? ? ?PreparedStatement ps = null;
 ? ? ? ?ResultSet rs = null;
 ? ? ? ?try {
 ? ? ? ? ? ?connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/muse?useSSL=false","root", "123465");
?
 ? ? ? ? ? ?// 3> 通过Statement对象执行SQL语句,并获得结果对象ResultSet。
 ? ? ? ? ? ?// ps = connection.prepareStatement("select name, age from tb_user");
 ? ? ? ? ? ?// ps = ps.executeQuery();
?
 ? ? ? ? ? ?ps = connection.prepareStatement("select name, age from tb_user where id = ?");
 ? ? ? ? ? ?// 设置参数:第一个参数,设置为 1
 ? ? ? ? ? ?ps.setInt(1, 1);
 ? ? ? ? ? ?rs = ps.executeQuery();
?
 ? ? ? ? ? ?// 4> 通过代码将ResultSet对象转化为POJO对象。
 ? ? ? ? ? ?while (rs.next()) {
 ? ? ? ? ? ? ? ?System.out.println(
 ? ? ? ? ? ? ? ? ? ? ? ?String.format("姓名:%s, 年龄:%d", rs.getString("name"),
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?rs.getInt("age")));
 ? ? ? ? ?  }
 ? ? ?  } catch (Throwable e) {
 ? ? ? ? ? ?System.out.println("error" + e.getMessage());
 ? ? ?  } finally {
 ? ? ? ? ? ?close(connection, ps, rs);
 ? ? ?  }
 ?  }
?
 ? ?// 5> 关闭数据库资源。
 ? ?private static void close(Connection connection, PreparedStatement ps, ResultSet rs) {
 ? ? ? ?try {
 ? ? ? ? ? ?// 判断非空,且没有关闭才执行关闭
 ? ? ? ? ? ?if (rs != null && !rs.isClosed()) {
 ? ? ? ? ? ? ? ?rs.close();
 ? ? ? ? ?  }
 ? ? ?  } catch (Throwable e) {
 ? ? ? ? ? ?System.out.println("rs.close error! " + e.getMessage());
 ? ? ?  }
?
 ? ? ? ?try {
 ? ? ? ? ? ?if (ps != null && !ps.isClosed()) {
 ? ? ? ? ? ? ? ?ps.close();
 ? ? ? ? ?  }
 ? ? ?  } catch (Throwable e) {
 ? ? ? ? ? ?System.out.println("ps.close error! " + e.getMessage());
 ? ? ?  }
?
 ? ? ? ?try {
 ? ? ? ? ? ?if (connection != null && !connection.isClosed()) {
 ? ? ? ? ? ? ? ?connection.close();
 ? ? ? ? ?  }
 ? ? ?  } catch (Throwable e) {
 ? ? ? ? ? ?System.out.println("connection.close error! " + e.getMessage());
 ? ? ?  }
 ?  }
}

HiBernate

优点

1> 将映射规则分离到XML/注解中,减少了代码的耦合度。

2> 无需管理数据库连接,只需配置响应的XML。

3> 一个会话,只需要操作Session对象即可。

4> 关闭资源,只关闭Session即可。

缺点:

1> 全表映射不便利,更新时需要发送所有字段。

2> 无法根据不同的条件组装不同的SQL。

3> 对于多表关联和复杂SQL查询支持较差,需要自己写SQL,返回后,需要自己将数据组装为POJO。

4> HQL性能较差,无法优化SQL。

5> 不能有效支持存储过程。

具体使用操作:

① 添加依赖

 ? ? ? ?<!-- Hibernate -->
 ? ? ? ?<dependency>
 ? ? ? ? ? ?<groupId>org.hibernate</groupId>
 ? ? ? ? ? ?<artifactId>hibernate-agroal</artifactId>
 ? ? ? ? ? ?<version>5.4.18.Final</version>
 ? ? ? ? ? ?<type>pom</type>
 ? ? ? ?</dependency>

② hibernate 配置文件(hibernate.conf.xml)

配置 数据库的相关属性指定映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
 ? ? ? ?"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 ? ? ? ?"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 ? ?<!-- 配置数据库连接 connection -->
 ? ?<session-factory>
 ? ? ? ?<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
 ? ? ? ?<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/muse?useSSL=false&amp;zeroDateTimeBehavior=CONVERT_TO_NULL</property>
 ? ? ? ?<property name="hibernate.connection.username">root</property>
 ? ? ? ?<property name="hibernate.connection.password">123465</property>
 ? ? ? ?<!-- 数据库方言 MySQL -->
 ? ? ? ?<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
 ? ? ? ?<!-- 格式化输出生成的SQL语句 -->
 ? ? ? ?<property name="hibernate.show_sql">true</property>
 ? ? ? ?<property name="hibernate.format_sql">true</property>
?
 ? ? ? ?<!-- 加载映射文件  -->
 ? ? ? ?<mapping resource="User.hbm.xml" />
 ? ?</session-factory>
</hibernate-configuration>

③ 映射文件(User.hbm.xml)

配置 实体类表字段 的映射关系

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
 ? ? ? ?"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 ? ? ? ?"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 ? ?<class name="vo.User" table="tb_user">
 ? ? ? ?<!-- name 为实体类属性; column 为表字段 -->
 ? ? ? ?<id name="id" column="id">
 ? ? ? ? ? ?<!-- 主键策略,用于插入的时候进行主键维护 -->
 ? ? ? ? ? ?<generator class="native"/>
 ? ? ? ?</id>
 ? ? ? ?<property name="name" column="name"/>
 ? ? ? ?<property name="age" column="age"/>
 ? ?</class>
</hibernate-mapping>

④ 代码实现(UserExecutor.java)

public class UserExecutor {
 ? ?public static void main(String[] args) {
 ? ? ? ?// 读取配置文件
 ? ? ? ?Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
 ? ? ? ?// 通过配置打开一个 session
 ? ? ? ?SessionFactory sessionFactory = configuration.buildSessionFactory();
?
 ? ? ? ?Session session = null;
 ? ? ? ?try {
 ? ? ? ? ? ?// 一个会话,只需要操作Session对象即可
 ? ? ? ? ? ?session = sessionFactory.openSession();
 ? ? ? ? ? ?// 通过 get 方法获取 id 为 2 的数据
 ? ? ? ? ? ?User user = session.get(User.class, 2L);
 ? ? ? ? ? ?System.out.println("user = " + user);
 ? ? ?  } catch (Throwable e) {
 ? ? ? ? ? ?System.out.println("error!" + e.getMessage());
 ? ? ?  } finally {
 ? ? ? ? ? ?if (session != null) {
 ? ? ? ? ? ? ? ?session.close();
 ? ? ? ? ? ? ? ?sessionFactory.close();
 ? ? ? ? ?  }
 ? ? ?  }
 ?  }
}

缺点:按照 hibernate 的方式拼装 sql 语句,不灵活,无法优化(sql 日志如下图)

MyBatis

1> 可以配置动态SQL。

2> 可以对SQL进行优化,并通过配置来决定SQL的映射规则。

3> 支持存储过程。

4> 具有自动映射功能,在注意命名规则的基础上,无需在写映射规则。

5> MyBatis提供接口编程的映射器,只需要一个接口和映射文件便可以运行【动态代理】。

6> 与代码耦合度低。

具体使用操作:

① 添加依赖

 ? ? ? ?<!-- MyBatis -->
 ? ? ? ?<dependency>
 ? ? ? ? ? ?<groupId>org.mybatis</groupId>
 ? ? ? ? ? ?<artifactId>mybatis</artifactId>
 ? ? ? ? ? ?<version>3.4.5</version>
 ? ? ? ?</dependency>

② 数据库环境配置文件(resources/sqlmap/mybatis/mysql/jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/muse?useUnicode=true&characterEncoding=utf-8&useSSL=false
username=root
password=123465

③ MyBatis 配置文件(resources/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>
?
 ? ?<!-- 加载数据库配置文件 -->
 ? ?<properties resource="sqlmap/mybatis/mysql/jdbc.properties" />
?
 ? ?<settings>
 ? ? ? ?<setting name="logImpl" value="STDOUT_LOGGING"/> <!-- 打印查询语句 -->
 ? ?</settings>
?
 ? ?<!-- 别名 -->
 ? ?<typeAliases>
 ? ? ? ?<package name="vo"/>
 ? ?</typeAliases>
?
 ? ?<!-- 配置数据库环境 -->
 ? ?<environments default="dev">
 ? ? ? ?<environment id="dev">
 ? ? ? ? ? ?<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>
?
 ? ?<!-- 数据库厂商标识 -->
 ? ?<databaseIdProvider type="DB_VENDOR"/>
?
 ? ?<!-- mappers 映射器 -->
 ? ?<mappers>
 ? ? ? ?<mapper resource="sqlmap/mybatis/mysql/UserMapper.xml"/>
 ? ?</mappers>
</configuration>

MyBatis提供接口编程的映射器,只需要一个接口和映射文件便可以运行

④ 映射文件(resources/sqlmap/mybatis/mysql/UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 对应着接口名称(下面⑤的接口名称) -->
<mapper namespace="mybatis.mapper.UserMapper">
?
 ? ?<sql id="allColumn">
 ? ? ?  id, name, age
 ? ?</sql>
?
 ? ?<select id="getUserById" parameterType="long" resultType="user">
 ? ? ?  select
 ? ? ? ? ? ?<include refid="allColumn"/>
 ? ? ?  from
 ? ? ? ? ?  tb_user
 ? ? ?  where
 ? ? ? ? ?  id = #{id}
 ? ?</select>
?
</mapper>

⑤ 接口(src/main/java/mybatis/mapper/UserMapper.java

public interface UserMapper {
?
 ? ?User getUserById(@Param("id") Long id);
?
}

⑥ 实例一个 sqlSession(src/main/java/mybatis/common/SqlSessionFactoryUtil.java)

public class SqlSessionFactoryUtil {
?
 ? ?private static SqlSessionFactory sqlSessionFactory;
?
 ? ?public static SqlSession openSqlSession() {
 ? ? ? ?// 单例实例一个 session
 ? ? ? ?// 第一次判断,提供效率
 ? ? ? ?if (sqlSessionFactory == null) {
 ? ? ? ? ? ?init();
 ? ? ?  }
 ? ? ? ?return sqlSessionFactory.openSession(true);
 ?  }
?
 ? ?private static SqlSessionFactory init() {
 ? ? ? ?InputStream inputStream = null;
 ? ? ? ?try {
 ? ? ? ? ? ?// 读取配置资源
 ? ? ? ? ? ?inputStream = Resources.getResourceAsStream("mybatis-config.xml");
 ? ? ?  } catch (IOException e) {
 ? ? ? ? ? ?e.printStackTrace();
 ? ? ?  }
?
 ? ? ? ?synchronized(SqlSessionFactoryUtil.class) {
 ? ? ? ? ? ?// 二次判断,判断是否已经有实例
 ? ? ? ? ? ?if (sqlSessionFactory == null) {
 ? ? ? ? ? ? ? ?sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 ? ? ? ? ?  }
 ? ? ? ? ? ?return sqlSessionFactory;
 ? ? ?  }
 ?  }
}

⑦ 通过 session 调用接口操作数据库(src/main/java/mybatis/UserExecuter.java)

public class UserExecuter {
 ? ?public static void main(String[] args) {
 ? ? ? ?SqlSession sqlSession = null;
 ? ? ? ?try {
 ? ? ? ? ? ?// 获取 session
 ? ? ? ? ? ?sqlSession = SqlSessionFactoryUtil.openSqlSession();
 ? ? ? ? ? ?// 获得接口
 ? ? ? ? ? ?UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 ? ? ? ? ? ?// 使用接口操作数据库
 ? ? ? ? ? ?User user = userMapper.getUserById(2L);
 ? ? ? ? ? ?System.out.println("user = " + user);
 ? ? ?  } catch (Throwable e) {
 ? ? ? ? ? ?System.out.println("error!" + e.getMessage());
 ? ? ?  } finally {
 ? ? ? ? ? ?// 关闭 session
 ? ? ? ? ? ?if (sqlSession != null) {
 ? ? ? ? ? ? ? ?sqlSession.close();
 ? ? ? ? ?  }
 ? ? ?  }
 ?  }
}

相比于 hibernate 的 sql 拼装,mybatis 的 sql 没有进行固定格式的格式,操作优化简单。


CRUD:

查询 Retrieve:

(1)基础查询:

① mybatis-config.xml 添加映射器

 ? ?<!-- mappers 映射器 -->
 ? ?<mappers>
 ? ? ? ?<mapper resource="sqlmap/mybatis/mysql/UserMapper.xml"/>
 ? ? ? ?<mapper resource="sqlmap/mybatis/mysql/UserContactMapper.xml"/>
 ? ?</mappers>

② 新建接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?Message getMessageById(@Param("id") Long id);
 ? ?
}

③ 新建映射器 MessageMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mybatis.mapper.MessageMapper">
?
 ? ?<sql id="allColumns">
 ? ? ?  id, msg_id, status, content, deleted, create_time, update_time
 ? ?</sql>
?
?
 ? ?<select id="getMessageById" parameterType="long" resultType="message">
 ? ? ?  select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ?  from
 ? ? ? ? ?  tb_message
 ? ? ?  where
 ? ? ? ? ?  id = #{id}
 ? ?</select>
?
</mapper>

④ 一个映射器,一个接口就能运行,测试类 MessageExecur.java

public class MessageExecuter {
 ? ?public static void main(String[] args) {
?
 ? ? ? ?SqlSession sqlSession = null;
 ? ? ? ?try {
 ? ? ? ? ? ?sqlSession = SqlSessionFactoryUtil.openSqlSession();
 ? ? ? ? ? ?MessageMapper messageMapper = sqlSession.getMapper(MessageMapper.class);
?
 ? ? ? ? ? ?/** 基础类型查询 **/
 ? ? ? ? ? ?Message message = messageMapper.getMessageById(1L);
 ? ? ? ? ? ?System.out.println("message = " + message);
?
 ? ? ?  } catch (Throwable e) {
 ? ? ? ? ? ?System.out.println("error!" + e.getMessage());
 ? ? ?  } finally {
 ? ? ? ? ? ?if (sqlSession != null) {
 ? ? ? ? ? ? ? ?sqlSession.close();
 ? ? ? ? ?  }
 ? ? ?  }
 ?  }
}

结果如下:

发现输出的实体结果:不为空的字段输出为空。

原因是:没有驼峰字段的映射?

解决方案:① 配置中开启自动驼峰映射

<!-- 自动映射的三种行为:不映射;部分映射;全部映射 NONE PARTIAL FULL -->
<setting name="autoMappingBehavior" value="PARTIAL"/> 
<!-- 配置驼峰转下划线 数据库中的下划线,转换Java Bean中的驼峰 -->
<setting name="mapUnderscoreToCamelCase" value="true"/> 

② 设置结果集映射 resultMap

 <resultMap id="messageVoReusltMap" type="vo.MessageVO">
 ? ? ? ?<id column="id" property="idVo"/>
 ? ? ? ?<result column="msg_id" property="msgIdVo"/>
 ? ? ? ?<result column="status" property="statusVo"/>
 ? ? ? ?<result column="content" property="contentVo"/>
 ? ? ? ?<result column="deleted" property="deletedVo"/>
 ? ? ? ?<result column="create_time" property="createTimeVo"/>
 ? ? ? ?<result column="update_time" property="updateTimeVo"/>
 ? ?</resultMap>
    
    <select id="getMessageVOById" parameterType="long" resultMap="messageVoReusltMap">
 ? ? ?  select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ?  from
 ? ? ? ? ?  tb_message
 ? ? ?  where
 ? ? ? ? ?  id = #{id}
 ? ?</select>

③ 结果:

(2)以 map 作为入参进行多个参数的查询

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?Message getMessageByMap(Map<String, Object> params);
 ? ?
}

② 映射器 MessageMapper.xml

    <select id="getMessageByMap" parameterType="map" resultType="message">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?id = #{id} and msg_id = #{msgId}
 ? ?</select>

③ 测试类 MessageExecur.java

    Map<String, Object> params = new HashMap<String, Object>();
    params.put("id", 1L);
    params.put("msgId", "msg_1");
    Message message = messageMapper.getMessageByMap(params);
    System.out.println("message = " + message);

④ 结果:

?

(3)以注解的方式,指定查询入参

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?Message getMessageByIdAndMsgId(@Param("id") Long id, @Param("msgId") String msgId);
 ? ?
}

② 映射器 MessageMapper.xml

    <select id="getMessageByIdAndMsgId" resultType="message">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?id = #{id} and msg_id = #{msgId}
 ? ?</select>

③ 测试类 MessageExecur.java

    Message message = messageMapper.getMessageByIdAndMsgId(1L, "msg_1");
    System.out.println("message = " + message);

(4)以实体的是方式,指定查询入参

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?Message getMessageByMessage(Message message);
 ? ?
}

② 映射器 MessageMapper.xml

    <select id="getMessageByMessage" parameterType="vo.Message" resultType="message">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?id = #{id} and msg_id = #{msgId}
 ? ?</select>

③ 测试类 MessageExecur.java

    Message params = new Message();
    params.setId(1L);
    params.setMsgId("msg_1");
    Message message = messageMapper.getMessageByMessage(params);
    System.out.println("message = " + message);

插入 Create:

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?int insert(Message message);
 ? ?
}

② 映射器 MessageMapper.xml

    <sql id="insertAllColumns">
 ? ? ? ?msg_id, status, content, deleted, create_time
 ? ?</sql>
?
    <insert id="insert" parameterType="message" keyProperty="id" >
 ? ? ? ?insert into tb_message(<include refid="insertAllColumns"/>) values(#{msgId}, #{status}, #{content},#{deleted}, #{createTime})
 ? ?</insert>

③ 测试类 MessageExecur.java

    Message message = new Message();
    message.setMsgId("msg_5");
    message.setDeleted(0);
    message.setStatus(1);
    message.setContent("dddd");
    message.setCreateTime(new Date());
    messageMapper.insert(message);
?
    sqlSession.commit();
    System.out.println("message = " + message);

④ 结果:

从结果可以看到,插入已经成功了,但直接输出的话,插入生成的数据并没有回显。

想要回显的话:① 再查一遍?

② 配置 useGeneratedKeys="true"

    <insert id="insert" parameterType="message" keyProperty="id" useGeneratedKeys="true">
 ? ? ?  insert into tb_message(<include refid="insertAllColumns"/>) values(#{msgId}, #{status}, #{content},#{deleted}, #{createTime})
 ? ?</insert>

⑤ 配置自动提交

配置了自动提交之后,上面测试类中的提交就可以不用了:// sqlSession.commit();

在 SqlSessionFactoryUtil.java 中给 openSession() 加上参数 true;

    public static SqlSession openSqlSession() {
 ? ? ? ?if (sqlSessionFactory == null) {
 ? ? ? ? ? ?init();
 ? ? ?  }
 ? ? ? ?return sqlSessionFactory.openSession(true);
 ?  }

更新 Update:

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?int updateContentById(@Param("id") Long id, @Param("content") String content);
 ? ?
}

② 映射器 MessageMapper.xml

    <update id="updateContentById">
 ? ? ? ?update tb_message set content=#{content} where id = #{id}
 ? ?</update>

③ 测试类 MessageExecur.java

    messageMapper.updateContentById(1L, "newContent1");

删除 Delete:

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?int deleteById(Long id);
 ? ?
}

② 映射器 MessageMapper.xml

    <delete id="deleteById" parameterType="long">
 ? ? ? ?delete from tb_message where id = #{id}
 ? ?</delete>

③ 测试类 MessageExecur.java

    messageMapper.deleteById(12L);

入参:

$与#的区别?

? $ 采用 值传递 的方式构建 SQL 语句

? # 采用 预编译 的方式构建 SQL 语句

举个例子:

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?Message getMessageByMsgId(@Param("msgId") String msgId);
 ? ?
}

② 映射器 MessageMapper.xml

    <select id="getMessageByMsgId" resultType="message">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?msg_id = #{msgId}
 ? ?</select>

③ 测试类 MessageExecur.java

    Message message = messageMapper.getMessageByMsgId("msg_1");
    System.out.println(message);

④ 结果:

#

<select id="getMessageByMsgId" resultType="message">
 ?  select
 ? ? ? ?<include refid="allColumns"/>
 ?  from
 ? ? ?  tb_message
 ?  where
 ? ? ?  msg_id = #{msgId}
</select>

?

$

<select id="getMessageByMsgId" resultType="message">
 ?  select
 ? ? ? ?<include refid="allColumns"/>
 ?  from
 ? ? ?  tb_message
 ?  where
 ? ? ?  msg_id = ${msgId}
</select>

?

SQL 注入的问题:

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?List<Message> getMessageByStringId(@Param("id") String id);
 ? ?
}

② 映射器 MessageMapper.xml

    <select id="getMessageByStringId" parameterType="string" resultType="message">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?id = #{id}
 ? ?</select>

③ 测试类 MessageExecur.java

    List<Message> message = messageMapper
 ? ? ? ? ? ? ? ? ?  .getMessageByStringId("1 or (select count(1) from tb_message) > 0");
 ? ? ? ? ? ?System.out.println("message = " + message);

④ 结果:

#

$


?

结果集:

存储结果集方式有哪些?

? map 方式存储结果集

? POJO 方式存储结果集

map:

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?Map getMessageMapById(@Param("id") Long id);
 ? ?
}

② 映射器 MessageMapper.xml

    <select id="getMessageMapById" parameterType="long" resultType="map">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?id = #{id}
 ? ?</select>

③ 测试类 MessageExecur.java

    Map map = messageMapper.getMessageMapById(1L);
    System.out.println("message = " + map);

pojo:

① 接口 MessageMapper.java

public interface MessageMapper {
?
 ? ?Message getMessageByMsgId(@Param("msgId") String msgId);
 ? ?
}

② 映射器 MessageMapper.xml

    <select id="getMessageByMsgId" resultType="message">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?msg_id = #{msgId}
 ? ?</select>

③ 测试类 MessageExecur.java

    Message message = messageMapper.getMessageByMsgId("msg_1");
    System.out.println(message);

级联:

Association 一对一

通过 id 使用 messageMapper 接口查询 message 信息,同时通过 一对一 级联查询 messageDetail 信息。

① 接口

MessageMapper.java

public interface MessageMapper {
?
 ? ?Map getMessageMapById(@Param("id") Long id);
 ? ?
}

MessageDetailMapper.java

public interface MessageDetailMapper {
?
 ? ?MessageDetail getMessageByMsgId(@Param("msgId") String msgId);
 ? ?
}

② 映射器

MessageDetailMapper.xml

    <sql id="allColumns">
 ? ? ?  id, msg_id, detail_content, create_time, update_time
 ? ?</sql>
?
 ? ?<select id="getMessageByMsgId" parameterType="string" resultType="vo.MessageDetail">
 ? ? ?  select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ?  from
 ? ? ? ? ?  tb_message_detail
 ? ? ?  where
 ? ? ? ? ?  msg_id = #{msgId}
 ? ?</select>

MessageMapper.xml

【 级联查询在 resultMap 中的 association 部分 】

 <resultMap id="messageAndDetailReusltMap" type="vo.Message">
 ? ? ? ?<id column="id" property="id"/>
 ? ? ? ?<result column="msg_id" property="msgId"/>
 ? ? ? ?<result column="status" property="status"/>
 ? ? ? ?<result column="content" property="content"/>
 ? ? ? ?<result column="deleted" property="deleted"/>
 ? ? ? ?<result column="create_time" property="createTime"/>
 ? ? ? ?<result column="update_time" property="updateTime"/>
 ? ? ? ?<association property="messageDetail" column="msg_id"
 ? ? ? ? ? ? ? ? ? ? select="mybatis.mapper.MessageDetailMapper.getMessageByMsgId" />
 ? ?</resultMap>
?
    <select id="getMessageAndMessageDetailById" parameterType="long" resultMap="messageAndDetailReusltMap">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumns"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_message
 ? ? ? ?where
 ? ? ? ? ? ?id = #{id}
 ? ?</select>

③ 测试类 MessageExecur.java

    Message message = messageMapper.getMessageAndMessageDetailById(1L);
    System.out.println("message = " + message);

④ 结果:

?

Collection 一对多

通过 id 使用 UserMapper接口查询 user 信息,同时通过 一对多 级联查询 UserContact 信息。

① 接口

UserMapper.java

public interface UserMapper {
?
 ? ?User getUserAndUserContactById(@Param("id") Long id);
?
}

UserContactMapper.java

public interface UserContactMapper {
?
 ? ?List<UserContact> getUserContactByUserId(@Param("userId") Long userId);
}

② 映射器

UserContactMapper.xml

    <sql id="allColumn">
 ? ? ?  id, user_id, contact_type, contact_value, create_time, update_time
 ? ?</sql>
?
 ? ?<select id="getUserContactByUserId" parameterType="long" resultType="vo.UserContact">
 ? ? ?  select
 ? ? ? ? ? ?<include refid="allColumn"/>
 ? ? ?  from
 ? ? ? ? ?  tb_user_contact
 ? ? ?  where
 ? ? ? ? ?  user_id=#{userId}
 ? ?</select>

UserMapper.xml

【 级联查询在 resultMap 中的 collection 部分 】

<resultMap id="userReuslt" type="vo.User">
 ? ? ? ?<id column="id" property="id"/>
 ? ? ? ?<result column="name" property="name"/>
 ? ? ? ?<result column="age" property="age"/>
 ? ? ? ?<collection property="userContacts" column="id"
 ? ? ? ? ? ? ? ? ? ?select="mybatis.mapper.UserContactMapper.getUserContactByUserId" />
 ? ?</resultMap>
?
    <select id="getUserAndUserContactById" parameterType="long" resultMap="userReuslt">
 ? ? ? ?select
 ? ? ? ? ? ?<include refid="allColumn"/>
 ? ? ? ?from
 ? ? ? ? ? ?tb_user
 ? ? ? ?where
 ? ? ? ? ? ?id = #{id}
 ? ?</select>

③ 测试类 MessageExecur.java

    User user = userMapper.getUserAndUserContactById(1L);
    System.out.println("user = " + user);

④ 结果:


?

缓存:

一级缓存

一级缓存默认开启

?但一级缓存只针对同一个 session,新 session 会失效

?

二级缓存

开启:

① 添加 cache 标签

② 手动提交

?

结果:


?

动态SQL

if

所有 if 都满足才有结果

① 接口 UserMapper.java

public interface UserMapper {
?
 ? ?List<User> getUserByUser(User user);
?
}

② 映射器 UserMapper.xml

<resultMap id="userResultMap" type="vo.User">
 ? ? ? ?<id column="id" property="id"/>
 ? ? ? ?<result column="name" property="name"/>
 ? ? ? ?<result column="age" property="age"/>
 ? ?</resultMap>
?
?
    <select id="getUserByUser" parameterType="vo.User" resultMap="userResultMap">
 ? ? ?  select id, name, age
 ? ? ?  from tb_user
 ? ? ?  where 1=1
 ? ? ? ?<if test="id != null">
 ? ? ? ? ?  and id = #{id}
 ? ? ? ?</if>
 ? ? ? ?<if test="name != null and name != ''">
 ? ? ? ? ?  and name = #{name}
 ? ? ? ?</if>
 ? ? ? ?<if test="age != null">
 ? ? ? ? ?  and age = #{age}
 ? ? ? ?</if>
 ? ?</select>

③ 测试 UserExecuter.java

    User userParam = new User();
    userParam.setName("muse");
    userParam.setId(1L);
    List<User> user = userMapper.getUserByUser(userParam);
    System.out.println("user = " + user);

choose--when--otherwise

choose 标签是按顺序判断其内部 when 标签中的 test 条件出否成立,如果有一个成立,则 choose 结束。当choose 中所有 when 的条件都不满则时,则执行 otherwise 中的 sql。类似于 Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。

① 接口 UserMapper.java

public interface UserMapper {
?
 ? ?List<User> getUserByUser2(User user);
?
}

② 映射器 UserMapper.xml

 <select id="getUserByUser2" parameterType="vo.User" resultMap="userResultMap">
 ? ? ?  select id, name, age
 ? ? ?  from tb_user
 ? ? ?  where 1=1
 ? ? ? ?<choose>
 ? ? ? ? ? ?<when test="id != null">
 ? ? ? ? ? ? ?  and id = #{id}
 ? ? ? ? ? ?</when>
 ? ? ? ? ? ?<when test="name != null and name != ''">
 ? ? ? ? ? ? ?  and name = #{name}
 ? ? ? ? ? ?</when>
 ? ? ? ? ? ?<otherwise>
 ? ? ? ? ? ? ?  and age is not null
 ? ? ? ? ? ?</otherwise>
 ? ? ? ?</choose>
 ? ?</select>

③ 测试 UserExecuter.java

    User userParam = new User();
    userParam.setName("muse");
    userParam.setId(1L);
    userParam.setAge(22);
    List<User> user = userMapper.getUserByUser2(userParam);
    System.out.println("user = " + user);

where

① 接口 UserMapper.java

public interface UserMapper {
?
 ? ?List<User> getUserByUser3(User user);
?
}

② 映射器 UserMapper.xml

    <select id="getUserByUser3" parameterType="vo.User" resultMap="userResultMap">
 ? ? ?  select
 ? ? ?  id, name, age from tb_user
 ? ? ? ?<where>
 ? ? ? ? ? ?<if test="id != null">
 ? ? ? ? ? ? ?  and id = #{id}
 ? ? ? ? ? ?</if>
 ? ? ? ?</where>
 ? ?</select>

③ 测试 UserExecuter.java

    User userParam = new User();
    userParam.setId(1L);
    List<User> user = userMapper.getUserByUser3(userParam);
    System.out.println("user = " + user);

trim

mybatis 的 trim 标签一般用于去除 sql 语句中多余的 关键字,逗号,或者给 sql 语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于选择性插入、更新、删除或者条件查询等操作。

属性描述
prefix给sql语句拼接的前缀
suffix给sql语句拼接的后缀
prefixOverrides去除sql语句前面的关键字或者字符
suffixOverrides去除sql语句后面的关键字或者字符

参考:mybatis trim标签的使用_wt_better的博客-CSDN博客_mybatis trim

① 接口 UserMapper.java

public interface UserMapper {
?
 ? ?List<User> getUserByUser4(User user);
?
}

② 映射器 UserMapper.xml

    <select id="getUserByUser4" parameterType="vo.User" resultMap="userResultMap">
 ? ? ?  select
 ? ? ?  id, name, age from tb_user
 ? ? ? ?<trim prefix="where" prefixOverrides="and">
 ? ? ? ? ?  and id = #{id}
 ? ? ? ?</trim>
 ? ?</select>

③ 测试 UserExecuter.java

    User userParam = new User();
    userParam.setId(1L);
    List<User> user = userMapper.getUserByUser4(userParam);
    System.out.println("user = " + user);

set

用于修改

① 接口 UserMapper.java

public interface UserMapper {
?
 ? ?int updateUserByUser(User user);
?
}

② 映射器 UserMapper.xml

    <update id="updateUserByUser" parameterType="vo.User">
 ? ? ?  update tb_user
 ? ? ? ?<set>
 ? ? ? ? ? ?<if test="name != null and name != ''">
 ? ? ? ? ? ? ?  name = #{name},
 ? ? ? ? ? ?</if>
 ? ? ? ? ? ?<if test="age != null">
 ? ? ? ? ? ? ?  age = #{age},
 ? ? ? ? ? ?</if>
 ? ? ? ?</set>
 ? ? ?  where id = #{id}
 ? ?</update>

③ 测试 UserExecuter.java

    User userParam = new User();
    userParam.setId(1L);
    userParam.setAge(222);
    userMapper.updateUserByUser(userParam);

foreach

① 接口 UserMapper.java

public interface UserMapper {
?
 ? ?List<User> getUserByIds(@Param("idList") List<Long> idList);
?
}

② 映射器 UserMapper.xml

    <select id="getUserByIds" resultMap="userResultMap">
 ? ? ?  select
 ? ? ?  id, name, age
 ? ? ?  from tb_user
 ? ? ?  where id in
 ? ? ? ?<foreach collection="idList" index="index" item="id" open="(" separator="," close=")">
 ? ? ? ? ?  #{id}
 ? ? ? ?</foreach>
 ? ?</select>

③ 测试 UserExecuter.java

    List<Long> ids = new ArrayList();
    ids.add(1L);
    ids.add(2L);
    ids.add(3L);
    ids.add(4L);
    List<User> users = userMapper.getUserByIds(ids);
    System.out.println("users = " + users);

concat & bind

都是用来模糊查询

① 接口 UserMapper.java

public interface UserMapper {
?
 ? ?List<User> getUserByName(@Param("name") String name);
?
}

② 映射器 UserMapper.xml

    <select id="getUserByName" parameterType="string" resultMap="userResultMap">
 ? ? ? ?<bind name="namePattern" value="'%' + name + '%'"/>
 ? ? ?  select
 ? ? ?  id, name, age
 ? ? ?  from
 ? ? ?  tb_user
 ? ? ?  where
 ? ? ?  name like #{namePattern}
 ? ? ? ?<!-- name like concat('%', #{name}, '%') -->
 ? ?</select>

③ 测试 UserExecuter.java

    List<User> users = userMapper.getUserByName("muse");
    System.out.println("users = " + users); 

动态代理

JDK 动态代理

JDK 动态代理是利用 反射机制 生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 进行代理处理。

① 接口

public interface MessageService {
 ? ?void sendMessage();
}

② 接口实现(被代理对象)

public class MessageServiceImpl implements MessageService {
 ? ?@Override
 ? ?public void sendMessage() {
 ? ? ? ?System.out.println("MessageServiceImpl.sendMessage");
 ?  }
}

③ 代理类 【实现 InvocationHandler 接口】

public class JdkProxy<T> implements InvocationHandler {
?
 ? ?T target;
?
 ? ?public T getProxy(T target) {
 ? ? ? ?this.target = target;
 ? ? ? ?return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
 ?  }
?
 ? ?@Override
 ? ?public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 ? ? ? ?System.out.println("JDK动态代理拦截开始!");
 ? ? ? ?Object result = method.invoke(target, args);
 ? ? ? ?System.out.println("JDK动态代理拦截结束!");
 ? ? ? ?return result;
 ?  }
}

④ 测试

public class Executer {
 ? ?public static void main(String[] args) {
 ? ? ? ?JdkProxy<MessageService> jdkProxy = new JdkProxy();
 ? ? ? ?MessageService messageService = jdkProxy.getProxy(new MessageServiceImpl());
 ? ? ? ?messageService.sendMessage();
 ?  }
}

CGLIB字动态代理

cglib 动态代理是利用 asm 开源包,将代理对象类的 clas s文件加载进来,通过修改其 字节码 生成子类来进行处理。

① 被代理对象类

public class PlayService {
 ? ?public void play() {
 ? ? ? ?System.out.println("PlayService.play");
 ?  }
}

② 代理类 【实现 MethodInterceptor 接口】

public class CglibProxy<T> implements MethodInterceptor {
?
 ? ?T target;
?
 ? ?public T getProxy(T target) {
 ? ? ? ?this.target = target;
 ? ? ? ?Enhancer enhancer = new Enhancer();
 ? ? ? ?enhancer.setSuperclass(target.getClass());
 ? ? ? ?enhancer.setCallback(this);
 ? ? ? ?return (T) enhancer.create();
 ?  }
?
 ? ?public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
 ? ? ? ?System.out.println("CGLIB动态代理拦截开始!");
 ? ? ? ?Object result = methodProxy.invokeSuper(o, objects);
 ? ? ? ?System.out.println("CGLIB动态代理拦截结束!");
 ? ? ? ?return result;
 ?  }
}

③ 测试

public class Executer {
 ? ?public static void main(String[] args) {
 ? ? ? ?CglibProxy<PlayService> cglibProxy = new CglibProxy();
 ? ? ? ?// 代理无接口服务类
 ? ? ? ?PlayService playService = cglibProxy.getProxy(new PlayService());
 ? ? ? ?playService.play();
?
// ? ? ?  CglibProxy<MessageService> cglibProxy1 = new CglibProxy();
// ? ? ?  // 代理有接口服务类【cglib动态代理:有无接口都可】
// ? ? ?  MessageService messageService = cglibProxy1.getProxy(new MessageServiceImpl());
// ? ? ?  messageService.sendMessage();
 ?  }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-11 23:51:22  更:2022-01-11 23:51:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:56:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码