Spring+SpringMVC+MyBatis深入学习及搭建(一)——MyBatis的基础知识
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6812311.html
1. 对原生态 jdbc 程序中问题总结
1.1 jdbc 程序
需求:使用 jdbc 查询 mysql 数据库中用户表的记录
statement: 向数据库中发送一个 sql 语句
预编译 statement:好处:提高数据库性能。
预编译 statement 向数据库中发送一个 sql 语句,数据库编译 sql 语句,并把编译的结果保存在数据库砖的缓存中。下次再发 sql 时,如果 sql 相同,则不会再编译,直接使用缓存中的。
jdbc 编程步骤:
1. 加载数据库驱动
2. 创建并获取数据库链接
3. 创建 jdbc statement 对象
4. 设置 sql 语句
5. 设置 sql 语句中的参数 (使用 preparedStatement)
6. 通过 statement 执行 sql 并获取结果
7. 对 sql 执行结果进行解析处理
8. 释放资源 (resultSet、preparedstatement、connection)
public class JDBCTest { public static void main(String[] args) { Connection connection = null; // 预编译的 Statement,使用预编译的 Statement 提高数据库性能 PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 加载数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 通过驱动管理类获取数据库链接 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root"); // 定义 sql 语句 ? 表示占位符 String sql = "select * from t_user where username = ?"; //获取预处理 statement preparedStatement = connection.prepareStatement(sql); // 设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的参数值 preparedStatement.setString(1, "王五"); // 向数据库发出 sql 执行查询,查询出结果集 resultSet = preparedStatement.executeQuery(); // 遍历查询结果集 while (resultSet.next()) { System.out.println(resultSet.getString("id") + ""+ resultSet.getString("username"));} } catch (Exception e) {e.printStackTrace(); } finally { //释放资源 if (resultSet != null) { try {resultSet.close(); } catch (SQLException e) {e.printStackTrace(); } } if (preparedStatement != null) { try {preparedStatement.close(); } catch (SQLException e) {e.printStackTrace(); } } if (connection != null) { try {connection.close(); } catch (SQLException e) {e.printStackTrace(); } } } } }
1.2 问题总结
上面代码的问题总结:
1. 数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能。
解决方案:使用数据库连接池管理数据库连接。
2. 将 sql 语句硬编码到 Java 代码中,如果 sql 语句修。改,需要重新编译 java 代码,不利于系统维护。
解决方案:将 sql 语句配置在 xml 配置文件中,即使 sql 变化, 不需要对 java 代码进行重新编译。
3. 向 preparedStatement 中设置参数,对占位符位置和设置参数值,硬编码在 Java 代码中,不利于系统维护。
解决方案:将 sql 语句及占位符和参数全部配置在 xml 中。
4. 从 resultSet 中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
解决方案:将查询的结果集,自动映射成 Java 对象。
2.MyBatis 框架
2.1MyBatis 是什么?
MyBatis 本是apache的一个开源项目iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis,实质上 Mybatis 对 ibatis 进行一些改进。
MyBatis 是一个优秀的持久层框架,它对 jdbc 的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建 connection、创建 statement、手动设置参数、结果集检索等 jdbc 繁杂的过程代码。
Mybatis 通过 xml 或注解的方式将要执行的各种 statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过 java 对象和 statement 中的 sql 进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射成 java 对象并返回。
2.2MyBatis 框架
1. mybatis 配置
SqlMapConfig.xml,此文件作为 mybatis 的全局配置文件,配置了 mybatis 的运行环境等信息。
mapper.xml 文件即 sql 映射文件,文件中配置了操作数据库的 sql 语句。此文件需要在 SqlMapConfig.xml 中加载。
2. 通过 mybatis 环境等配置信息构造 SqlSessionFactory 即会话工厂
3. 由会话工厂创建 sqlSession 即会话,操作数据库需要通过 sqlSession 进行。
4. mybatis 底层自定义了 Executor 执行器接口操作数据库,Executor 接口有两个实现,一个是基本执行器、一个是缓存执行器。
5. Mapped Statement 也是 mybatis 一个底层封装对象,它包装了 mybatis 配置信息及 sql 映射信息等。mapper.xml 文件中一个 sql 对应一个 Mapped Statement 对象,sql 的 id 即是 Mapped statement 的 id。
6. Mapped Statement 对 sql 执行输入参数进行定义,包括 HashMap、基本类型、pojo,Executor 通过 Mapped Statement 在执行 sql 前将输入的 java 对象映射至 sql 中,输入参数映射就是 jdbc 编程中对 preparedStatement 设置参数。
7. Mapped Statement 对 sql 执行输出结果进行定义,包括 HashMap、基本类型、pojo,Executor 通过 Mapped Statement 在执行 sql 后将输出结果映射至 java 对象中,输出结果映射过程相当于 jdbc 编程中对结果的解析处理过程。
3. 入门程序
3.1 需求
根据用户 id(主键)查询用户信息
根据用户名称模糊查询用户信息
添加用户
删除用户
更新用户
3.2 所需 jar 包
MyBatis 下载地址:https://github.com/mybatis/mybatis-3/releases
mybatis-3.4.4.jar :核心包
mysql-connector-java-5.1.jar:mysql 的驱动包
3.3 工程结构
3.4 log4j.properties
# Global logging configuration
#在开发的环境下,日志级别要设置成 DEBUG,生产环境设置成 info 或 error
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3.5 SqlMapConfig.xml
MyBatis 核心配置文件,配置 MyBatis 的运行环境,数据源、事务等。
<?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> <!-- 和 spring 整合后 environments 配置将废除--> <environments default="development"> <environment id="development"> <!-- 使用 jdbc 事务管理, 事务控制由 mybatis 管理--> <transactionManager type="JDBC" /> <!-- 数据库连接池, 由 mybatis 管理--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <!-- 加载映射文件 --> <mappers> <mapper resource="sqlmap/User.xml"/> </mappers> </configuration>
3.6 根据用户 id(主键)查询用户信息
3.6.1 创建 po 类
package joanna.yan.mybatis.entity;import java.sql.Date;
public class User {
//属性名称和数据库字段名称保持一致
private int id;
private String username;
private Date birthday;
private String sex;
private String address;</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> User(String username, Date birthday, String sex, String address) { </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.username =<span style="color: rgba(0, 0, 0, 1)"> username; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.birthday =<span style="color: rgba(0, 0, 0, 1)"> birthday; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sex =<span style="color: rgba(0, 0, 0, 1)"> sex; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.address =<span style="color: rgba(0, 0, 0, 1)"> address; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> User(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id, String username, Date birthday, String sex, String address) { </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.username =<span style="color: rgba(0, 0, 0, 1)"> username; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.birthday =<span style="color: rgba(0, 0, 0, 1)"> birthday; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sex =<span style="color: rgba(0, 0, 0, 1)"> sex; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.address =<span style="color: rgba(0, 0, 0, 1)"> address; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getUsername() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> username; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setUsername(String username) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.username =<span style="color: rgba(0, 0, 0, 1)"> username; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getSex() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sex; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setSex(String sex) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sex =<span style="color: rgba(0, 0, 0, 1)"> sex; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getAddress() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> address; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setAddress(String address) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.address =<span style="color: rgba(0, 0, 0, 1)"> address; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getBirthday() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> birthday; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setBirthday(Date birthday) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.birthday =<span style="color: rgba(0, 0, 0, 1)"> birthday; } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> "User [id=" + id + ", username=" + username + ", sex=" +<span style="color: rgba(0, 0, 0, 1)"> sex </span>+ ", address=" + address + ", birthday=" + birthday + "]"<span style="color: rgba(0, 0, 0, 1)">; }
}
3.6.2 映射文件
映射文件命名:
User.xml(原始的 ibatis 的命名方式),mapper 代理开发映射文件名称叫 XXXMapper.xml, 比如:UserMapper.xml、ItemsMapper.xml。
在映射文件中配置 sql 语句。
<?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"> <!--namespace 命名空间,作用就是对 sql 进行分类化的管理,理解为 sql 隔离 注意:使用 mapper 代理开发时,namespace 有特殊作用 --> <mapper namespace="test"> <!--在映射文件中配置很多 sql 语句 --> <!--需求:通过 id 查询用户表的记录 --> <!--id:标识映射文件中的 sql,称为 statement 的 id。将 sql 语句封装在 mapperStatement 的对象中,所有 id 称为 Statement 的 id; parameterType:指定输入参数的类型,这里指定 int 型; #{}: 表示一个占位符; #{id}: 其中 id 表示接收输入的参数,参数名称就是 id,如果输入参数是简单类型,#{} 中的参数名可以任意,可以是 value 或其它名称; resultType:指定输出结果所映射的 Java 对象类型,select 指定 resultType 表示将单条记录映射成 Java 对象。 --> <select id="findUserById" parameterType="java.lang.Integer" resultType="joanna.yan.mybatis.entity.User"> select * from user where id=#{id} </select> </mapper>
3.6.3 在 SqlMapConfig.xml 中加载映射文件
<!-- 加载映射文件 --> <mappers> <mapper resource="sqlmap/User.xml"/> </mappers>
3.6.4 程序编写
public class MybatisFirst {@Test </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> findUserByIdTest(){ </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">mybatis的配置文件</span> String resource="SqlMapConfig.xml"<span style="color: rgba(0, 0, 0, 1)">; InputStream inputStream</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; SqlSession sqlSession</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { inputStream</span>=<span style="color: rgba(0, 0, 0, 1)">Resources.getResourceAsStream(resource); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">1.创建会话工厂,传入mybatis的配置文件信息</span> SqlSessionFactory factory=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactoryBuilder().build(inputStream); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2.通过工厂得到SqlSession</span> sqlSession=<span style="color: rgba(0, 0, 0, 1)">factory.openSession(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">3.通过SqlSession操作数据库 </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">参数一:映射文件中的statement的id,等于namespace+"."+statement的id; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">参数二:指定和映射文件中所匹配的parameterType类型的参数; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">sqlSession.selectOne结果是与映射文件所匹配的resultType类型的对象; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">selectOne:查询一条结果</span> User user=sqlSession.selectOne("test.findUserById", 1<span style="color: rgba(0, 0, 0, 1)">); System.out.println(user.toString()); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) { e.printStackTrace(); }</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)">{ </span><span style="color: rgba(0, 0, 255, 1)">if</span>(sqlSession!=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){ sqlSession.close(); } </span><span style="color: rgba(0, 0, 255, 1)">if</span>(inputStream!=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){ </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { inputStream.close(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) { e.printStackTrace(); } } } }
}
3.7 根据用户名称模糊查询用户信息
3.7.1 映射文件
使用 User.xml,添加根据用户名称模糊查询用户信息的 sql 语句。
<!-- 需求:根据用户名称模糊查询用户信息,可能返回多条数据 resultType:指定的就是单条记录所映射的 Java 类型; ${}:表示拼接 sql 字符串,将接收到的参数内容不加任何修饰的拼接在 sql 中。使用 ${} 拼接 sql,可能会引起 sql 注入; ${value}:接收输入参数的内容,如果传入的是简单类型,${} 中只能使用 value --> <select id="findUserByName" parameterType="java.lang.String" resultType="joanna.yan.mybatis.entity.User"> select * from user where username LIKE '%${value}%' </select>
3.7.2 程序编写
@Test public void findUserByNameTest(){ //mybatis 的配置文件 String resource="SqlMapConfig.xml"; InputStream inputStream=null; SqlSession sqlSession=null; try { inputStream=Resources.getResourceAsStream(resource); //1. 创建会话工厂,传入 mybatis 的配置文件信息 SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream); //2. 通过工厂得到 SqlSession sqlSession=factory.openSession(); //3. 通过 SqlSession 操作数据库 //参数一:映射文件中的 statement 的 id,等于 namespace+"."+statement 的 id; //参数二:指定和映射文件中所匹配的 parameterType 类型的参数; //sqlSession.selectOne 结果是与映射文件所匹配的 resultType 类型的对象; //list 中的 user 和 resultType 类型一致 List<User> list=sqlSession.selectList("test.findUserByName", "小明"); System.out.println(list); } catch (IOException e) {e.printStackTrace(); }finally{ if(sqlSession!=null){sqlSession.close(); } if(inputStream!=null){ try {inputStream.close(); } catch (IOException e) {e.printStackTrace(); } } } }
3.8 添加用户
3.8.1 映射文件
在 User.xml 配置添加用户的 statement(多个 sql)。
<!-- 需求:添加用户 parameterType: 指定输入的参数类型是 pojo(包括用户信息); #{}:中指定 pojo 的属性名称,接收到 pojo 对象的属性值,mybatis 通过 ONGL(类似于 struts2 的 OGNL)获取对象的属性值 --> <insert id="insertUser" parameterType="joanna.yan.mybatis.entity.User"> insert into user (username,sex,address,birthday) values (#{username},#{sex},#{address},#{birthday}) </insert>
3.8.2 程序编写
@Test public void insertUserTest(){ //mybatis 的配置文件 String resource="SqlMapConfig.xml"; InputStream inputStream=null; SqlSession sqlSession=null; try { inputStream=Resources.getResourceAsStream(resource); //1. 创建会话工厂,传入 mybatis 的配置文件信息 SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream); //2. 通过工厂得到 SqlSession sqlSession=factory.openSession(); User user=new User("yan",new Date(System.currentTimeMillis()),"女", "上海"); //3. 通过 SqlSession 操作数据库 //参数一:映射文件中的 statement 的 id,等于 namespace+"."+statement 的 id; //参数二:指定和映射文件中所匹配的 parameterType 类型的参数; sqlSession.insert("test.insertUser",user); //提交事务 sqlSession.commit(); System.out.println(user.getId()); } catch (IOException e) {e.printStackTrace(); }finally{ if(sqlSession!=null){sqlSession.close(); } if(inputStream!=null){ try {inputStream.close(); } catch (IOException e) {e.printStackTrace(); } } } }
3.8.3 自增主键返回
mysql 自增主键:执行 insert 提交之前自动生成一个自增主键。
通过 Mysql 函数获取到刚插入记录的自增主键:LAST_INSERT_ID()
是 insert 之后调用此函数。
修改 insertUser 定义:
<!-- 需求:添加用户 parameterType: 指定输入的参数类型是 pojo(包括用户信息); #{}:中指定 pojo 的属性名称,接收到 pojo 对象的属性值,mybatis 通过 ONGL(类似于 struts2 的 OGNL)获取对象的属性值 --> <insert id="insertUser" parameterType="joanna.yan.mybatis.entity.User"> <!-- 将 insert 插入的数据的主键返回到 User 对象中; select last_insert_id():得到刚 inser 进去记录的主键值,只适用于自增主键; keyProperty:将查询到的主键值,设置到 parameterType 指定的对象的那个属性; order:select last_insert_id() 的执行顺序,相对于 insert 语句来说它的执行顺序; resultType:指定 select last_insert_id() 的结果类型; --> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select last_insert_id() </selectKey> insert into user (username,sex,address,birthday) values (#{username},#{sex},#{address},#{birthday}) </insert>
3.8.4 非自增主键返回(使用 uuid())
使用 mysql 的 uuid() 函数生成主键,需要修改表中 id 字段类型为 String,长度设置为 35 位。
执行思路:
先通过 uuid() 查询到主键,将主键输入到 sql 语句中。
执行 uuid() 语句顺序相对于 insert 语句之前执行。
<!-- 需求:添加用户 parameterType: 指定输入的参数类型是 pojo(包括用户信息); #{}:中指定 pojo 的属性名称,接收到 pojo 对象的属性值,mybatis 通过 ONGL(类似于 struts2 的 OGNL)获取对象的属性值 --> <insert id="insertUser" parameterType="joanna.yan.mybatis.entity.User"><!--使用mysql的uuid(),实现非自增主键的返回; 执行过程:通过uuid()得到主键,将主键设置到user对象的id的属性中,其次,在inser执行时,从user对象中取出id属性值; </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">selectKey </span><span style="color: rgba(255, 0, 0, 1)">keyProperty</span><span style="color: rgba(0, 0, 255, 1)">="id"</span><span style="color: rgba(255, 0, 0, 1)"> order</span><span style="color: rgba(0, 0, 255, 1)">="BEFORE"</span><span style="color: rgba(255, 0, 0, 1)"> resultType</span><span style="color: rgba(0, 0, 255, 1)">="java.lang.String"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> select uuid() </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">selectKey</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> insert into user (id,username,sex,address,birthday) values (#{id},#{username},#{sex},#{address},#{birthday}) </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">insert</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
通过 oracle 的序列生成主键:
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String"> SELECT 序列名.nextval() </selectKey> insert into user(id,username,birthday,sex,address) value(#{id},#{username},#{birthday},#{sex},#{address})
3.9 删除用户和更新用户
3.9.1 映射文件
<!-- 需求:删除用户 --> <delete id="deleteUser" parameterType="java.lang.Integer"> delete from user where id=#{id} </delete> <!-- 需求:更新用户 注意:id 必须存在 --> <update id="updateUser" parameterType="joanna.yan.mybatis.entity.User"> update user set username=#{username},sex=#{sex},address=#{address},birthday=#{birthday} where id=#{id} </update>
3.9.2 程序编写
@Test public void deleteUserTest(){ //mybatis 的配置文件 String resource="SqlMapConfig.xml"; InputStream inputStream=null; SqlSession sqlSession=null; try { inputStream=Resources.getResourceAsStream(resource); //1. 创建会话工厂,传入 mybatis 的配置文件信息 SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream); //2. 通过工厂得到 SqlSession sqlSession=factory.openSession(); //3. 通过 SqlSession 操作数据库 //参数一:映射文件中的 statement 的 id,等于 namespace+"."+statement 的 id; //参数二:指定和映射文件中所匹配的 parameterType 类型的参数; sqlSession.delete("test.deleteUser",3); //提交事务 sqlSession.commit();} catch (IOException e) {e.printStackTrace(); }finally{ if(sqlSession!=null){sqlSession.close(); } if(inputStream!=null){ try {inputStream.close(); } catch (IOException e) {e.printStackTrace(); } } } }@Test </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> updateUserTest(){ </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">mybatis的配置文件</span> String resource="SqlMapConfig.xml"<span style="color: rgba(0, 0, 0, 1)">; InputStream inputStream</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; SqlSession sqlSession</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { inputStream</span>=<span style="color: rgba(0, 0, 0, 1)">Resources.getResourceAsStream(resource); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">1.创建会话工厂,传入mybatis的配置文件信息</span> SqlSessionFactory factory=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactoryBuilder().build(inputStream); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2.通过工厂得到SqlSession</span> sqlSession=<span style="color: rgba(0, 0, 0, 1)">factory.openSession(); User user</span>=<span style="color: rgba(0, 0, 255, 1)">new</span> User(2,"yan",<span style="color: rgba(0, 0, 255, 1)">new</span> Date(System.currentTimeMillis()), "女", "上海"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">3.通过SqlSession操作数据库 </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">参数一:映射文件中的statement的id,等于namespace+"."+statement的id; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">参数二:指定和映射文件中所匹配的parameterType类型的参数; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">根据id更新用户</span> sqlSession.update("test.updateUser"<span style="color: rgba(0, 0, 0, 1)">,user); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">提交事务</span>
sqlSession.commit();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(sqlSession!=null){
sqlSession.close();
}
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.10 总结
3.10.1 parameterType
在映射文件中通过 parameterType 指定输入参数的类型。
3.10.2 resultType
在映射文件中通过 resultType 指定输出结果的类型
3.10.3 #{} 和 ${}
#{} 表示一个占位符,#{} 接收输入参数。#{} 可以有效防止 sql 注入。类型可以是简单类型,pojo、hashmap。如果接收简单类型,#{} 中可以写成 value 或其它名称。
#{} 接收 pojo 对象值,通过 OGNL 读取对象中的属性值,通过属性. 属性. 属性... 的方式获取对象属性值。
${} 表示一个拼接符号,拼接 sql 串,会引起 sql 注入存在安全隐患,所以不建议使用 ${}。${} 接收输入参数,类型可以是简单类型,pojo、hashmap。如果接收简单类型,${} 中只能写成 value。
${} 接收 pojo 对象值,通过 OGNL 读取对象中的属性值,通过属性. 属性. 属性... 的方式获取对象属性值。
3.10.4 selectOne 和 selectList
selectOne 查询一条记录,如果使用 selectOne 查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList 可以查询一条或多条记录。
3.11 MyBatis 和 Hibernate 本质区别和应用场景
hibernate:是一个标准 ORM 框架(对象关系映射)。入门门槛较高,不需要程序员写 sql,sql 语句自动生成了。对 sql 语句进行优化、修改比较困难。
应用场景:
使用于需要变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。。。
mybatis: 专注是 sql 本身,需要程序员之家编写 sql 语句,sql 修改、优化比较方便。mybatis 是一个不完全的 ORM 框架,虽然程序员自己写 sql,mybatis 也可以实现映射(输入映射、输出映射)。
应用场景:
适用与需求变化较多的项目,比如:互联网项目。
如果此文对您有帮助,微信打赏我一下吧 ~