Mybatis(一)

    xiaoxiao2022-07-07  205

    1、为什么学习Mybatis

    Mybatis就是类似于hibernate的orm持久层框架。

    为什么学Mybatis?

    目前最主流的持久层框架为hibernate与mybatis,而且国内目前情况使用Mybatis的公司比hibernate要多。Hibernate学习门槛不低,要精通门槛更高。门槛高在怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate缓存与数据加载策略方面需要你的经验和能力都很强才行。国内目前前的情况精通hibernate技术大牛非常少。sql优化方面,Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。当然了,Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。说得更深入一些,如果有个查询要关联多张表,比如5张表,10张表时,而且,我们要取的字段只是其中几张表的部分字段。这时用hibernate时就会显得非常力不从心。就算用hibernate的sqlquery,后续的维护工作也会让人发狂。

    2、JDBC编程回顾与存在的问题分析

    2.1 开发步骤

    导入数据脚本,在课前资料中有创建工程,导入mysql jar包编码

    2.2 Jdbc访问数据库的过程

    加载数据库驱动创建数据库连接创建statement设置sql语句设置查询参数执行查询,得到ResultSet解析结果集ResultSet释放资源 package mybatis.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JdbcTest { // 加载驱动 // 创建连接 // 设置sql语句 // 创建Statement // 设置参数 // 执行查询,得到ResultSet // 遍历ResultSet,输出结果 // 释放资源 public static void main(String[] args) { Connection connection = null; 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", "123456"); // 定义sql语句 ?表示占位符 String sql = "select * from 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) { // TODO Auto-generated catch block e.printStackTrace(); } } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }

    2.3 Jdbc存在的问题

    频繁创建和打开、关闭数据连接,太消耗资源Sql语句存在硬编码,不利于维护Sql参数设置硬编码,不利于维护结果集获取与遍历复杂,存在硬编码,不利于维护,期望能够查询后返回一个java对象

    3、Mybatis介绍

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。Mybatis是面向sql的持久层框架,他封装了jdbc访问数据库的过程,我们开发,只需专注于sql语句本身的拼装,其它复杂的过程全部可以交给mybatis去完成。

    4、Mybaits入门

    4.1 工程搭建

    4.1.1 导入依赖的jar包

    4.1.2 配置SqlMapConfig.xml

    新建一个Source Folder(注意不是Folder)用于存放SqlMapConfig.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"> <!--dtd的模式就是要求标签出现的顺序必须按照其(configuration)顺序来 --> <configuration> <!-- 和spring整合后 environments配置将废除 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <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="123456" /> </dataSource> </environment> </environments> </configuration>

    4.1.3 配置log4j.properties

    在config下创建log4j.properties如下: # Global logging configuration 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

    4.1.4 配置实体类

    package mybatis.pojo; import java.util.Date; public class User { private Integer id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 public User() { super(); // TODO Auto-generated constructor stub } public User(String username, String sex, Date birthday, String address) { super(); this.username = username; this.sex = sex; this.birthday = birthday; this.address = address; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + ", uuid2=" + uuid2 + "]"; } }

    4.1.5 配置sql查询的映射文件

    粘贴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语句,后继有重要作用 --> <!-- #{}:占位符,相当于jdbc的问号? --> <!-- ${}:字符串拼接指令,如果入参是普通数据类型{ }内部只写value --> <mapper namespace="user"> <!-- id:sql id,语句的唯一标识 parameterType:入参的数据类型 resultType:返回结果的数据类型 --> <select id="getUserById" parameterType="int" resultType="mybatis.pojo.User"> SELECT `id`, `username`, `birthday`, `sex`, `address` FROM `user` WHERE id=#{id}; </select> <!-- resultType:如果返回结果为集合时,只需设置为每一个元素的数据类型 --> <select id="getUserByUserName" parameterType="string" resultType="mybatis.pojo.User"> SELECT `id`, `username`, `birthday`, `sex`, `address` FROM `user` <!-- WHERE username LIKE #{name}; --> WHERE username LIKE '%${value}%'; </select> </mapper>

    4.1.6 加载映射文件

    在SqlMapConfig中添加 <!-- 加载映射文件 --> <mappers> <!--当前目录下 --!> <mapper resource="mybatis/user.xml" /> </mappers>

    4.2 编写测试代码

    @Test public void testGetUserById() throws Exception { // 创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder(); // 创建核心配置文件的输入流 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 通过输入流创建SqlSessionFactory工厂对象 SqlSessionFactory sqlSessionFactory = ssfb.build(inputStream); // 创建SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行查询,参数一:sql id ;参数二:入参 User user = sqlSession.selectOne("user.getUserById", 1); // 输出结果 System.out.println(user); // 释放资源 sqlSession.close(); }

    4.3 抽取工具类

    package mybatis.utils; import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /** * SqlSessionFactory工具类 * @author Administrator * */ public class SqlSessionFactoryUtils { private static SqlSessionFactory sqlSessionFactory; static { try { // 创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder(); // 创建核心配置文件的输入流 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); // 通过输入流创建SqlSessionFactory工厂对象 sqlSessionFactory = ssfb.build(inputStream); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 获取SqlSessionFactory * * @return */ public static SqlSessionFactory getSqlSessionFactory() { return sqlSessionFactory; } }

    4.4 编写模糊查询的代码

    @Test public void testGetUserByUserName() { // 获取SqlSessionFactory SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 创建SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 执行查询,参数一:sql id ;参数二:入参 //(user.xml配置中的第一种写法) // List<User> list = sqlSession.selectList("user.getUserByUserName","%张%"); //(user.xml配置中的第二种写法) List<User> list = sqlSession.selectList("user.getUserByUserName", "张"); // 输出结果 for (User user : list) { System.out.println(user); } // 释放资源 sqlSession.close(); }

    4.5 添加用户

    4.5.1 编写user.xml配置文件

    <!--useGeneratedKeys:使用自增 --> <!--keyProperty:与之配套使用,这里是user的主键 --> <!--插入用户 --> <insert id="insertUser" parameterType="mybatis.pojo.User" useGeneratedKeys="true" keyProperty="id"> <!-- selectKey:主键返回; --> <!-- keyProperty:user中的主键属性; --> <!-- resultType:主键数据类型 ; --> <!-- order:指定selectKey何时执行;AFTER表示之后 --> <!-- <selectKey keyProperty="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID(); </selectKey> --> INSERT INTO `user` (`username`, `birthday`, `sex`, `address`) VALUES( #{username}, #{birthday}, #{sex}, #{address} ) ; </insert> 注: useGeneratedKeys="true" keyProperty="id" 等价于 <selectKey keyProperty="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID(); </selectKey>

    4.5.2 编写测试代码

    @Test public void testInsertUser() throws Exception{ // 获取SqlSessionFactory SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 创建SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); String str = "2019-03-05"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date d = sdf.parse(str); User user=new User("小东2", "1", d, "江苏南京"); /* User user =new User(); user.setUsername("小東"); user.setSex("1"); user.setBirthday(new Date()); user.setAddress("江蘇南京");*/ sqlSession.insert("user.insertUser",user); System.out.println(user); // 提交事务,Mybatis默认jdbc事务是不提交的,或者在openSession方法中设置参数为true,表示自动提交 sqlSession.commit(); // 释放资源 sqlSession.close(); }

    4.5.3 uuid的使用

    假如插入的表没有主键,可以使用uuid给它分配个主键

    配置user.xml

    注:在使用uuid之前数据库user表要先加上uuid2字段、user的pojo也要加上相应属性 <!--useGeneratedKeys:使用自增 --> <!--keyProperty:与之配套使用,这里是user的主键 --> <!--插入用户 --> <insert id="insertUserUUID" parameterType="mybatis.pojo.User" useGeneratedKeys="true" keyProperty="id"> <!-- selectKey:主键返回; --> <!-- keyProperty:user中的主键属性; --> <!-- resultType:主键数据类型 ; --> <!-- order:指定selectKey何时执行;AFTER表示之后 --> <selectKey keyProperty="uuid2" resultType="string" order="BEFORE"> SELECT UUID() </selectKey> INSERT INTO `user` (`username`, `birthday`, `sex`, `address`, `uuid2`) VALUES( #{username}, #{birthday}, #{sex}, #{address}, #{uuid2}) ; </insert> 注:这里开启了<selectKey keyProperty="uuid2" resultType="string" order="BEFORE"> SELECT UUID() </selectKey> useGeneratedKeys="true" keyProperty="id" 就默认不生效了!

    编写测试代码

    @Test public void testInsertUserUUID() throws Exception{ // 获取SqlSessionFactory SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 创建SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); /*String str = "2019-03-05"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date d = sdf.parse(str); User user=new User("小东2", "1", d, "江苏南京");*/ User user =new User(); user.setUsername("小222"); user.setSex("1"); user.setBirthday(new Date()); user.setAddress("南京"); sqlSession.insert("user.insertUserUUID",user); System.out.println(user); // 提交事务,Mybatis默认jdbc事务是不提交的,或者在openSession方法中设置参数为true,表示自动提交 sqlSession.commit(); // 释放资源 sqlSession.close(); }

    4.6 修改用户

    4.6.1 编写user.xml文件

    <!-- 更新用户 --> <update id="updateUser" parameterType="mybatis.pojo.User"> UPDATE `user` SET `username` = #{username} WHERE `id` = #{id}; </update>

    4.6.2 编写测试代码

    @Test public void testupdateUser() throws Exception{ // 获取SqlSessionFactory SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 创建SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); /*String str = "2019-03-05"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date d = sdf.parse(str); User user=new User("小东2", "1", d, "江苏南京");*/ User user =new User(); user.setId(56); user.setUsername("小东2222"); sqlSession.update("user.updateUser",user); System.out.println(user); // 提交事务,Mybatis默认jdbc事务是不提交的,或者在openSession方法中设置参数为true,表示自动提交 sqlSession.commit(); // 释放资源 sqlSession.close(); }

    4.7 删除用户

    4.7.1 编写user.xml文件

    <!-- 删除用户 --> <delete id="deleteUser" parameterType="int"> DELETE FROM `user` WHERE `id` = #{id} ; </delete>

    4.7.2 编写测试代码

    @Test public void testdeleteUser() throws Exception{ // 获取SqlSessionFactory SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 创建SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); /*String str = "2019-03-05"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date d = sdf.parse(str); User user=new User("小东2", "1", d, "江苏南京");*/ sqlSession.delete("user.deleteUser",54); // 提交事务,Mybatis默认jdbc事务是不提交的,或者在openSession方法中设置参数为true,表示自动提交 sqlSession.commit(); // 释放资源 sqlSession.close(); }

    4.8 Mybatis入门小结与Mybatis架构图

    5、Mybatis Dao开发方式

    5.1 原始Dao开发方法

    5.1.1 使用原有的user映射文件,不需修改

    5.1.2 新建个UserDao接口

    package mybatis.dao; import java.util.List; import mybatis.pojo.User; /** * 用户信息持久化接口 * @author Administrator * */ public interface UserDao { /** * 根据用户ID查询用户信息 * @param id * @return */ User getUserById(Integer id); /** * 根据用户名查找用户列表 * @param userName * @return */ List<User> getUserByUserName(String userName); /** * 添加用户 * @param user */ void insertUser(User user); }

    5.1.3 新建个UserDaoImpl接口实现类

    package mybatis.dao.impl; import java.util.List; import org.apache.ibatis.session.SqlSession; import mybatis.dao.UserDao; import mybatis.pojo.User; import mybatis.utils.SqlSessionFactoryUtils; public class UserDaoImpl implements UserDao{ @Override public User getUserById(Integer id) { SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(); User user=sqlSession.selectOne("user.getUserById", id); sqlSession.close(); return user; } @Override public List<User> getUserByUserName(String userName) { SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(); List<User> list=sqlSession.selectList("user.getUserByUserName", userName); sqlSession.close(); return list; } @Override public void insertUser(User user) { SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(true); sqlSession.insert("user.insertUser", user); //sqlSession.commit(); sqlSession.close(); } }

    5.1.4 使用Dao测试

    package mybatis.test; import java.text.SimpleDateFormat; import java.util.List; import org.junit.Test; import mybatis.dao.UserDao; import mybatis.dao.impl.UserDaoImpl; import mybatis.pojo.User; public class UserDaoImplTest { @Test public void testGetUserById() { UserDao userDao=new UserDaoImpl(); User user=userDao.getUserById(30); System.out.println(user); } @Test public void testGetUserByUserName() { UserDao userDao=new UserDaoImpl(); List<User> list=userDao.getUserByUserName("小"); for(User user:list){ System.out.println(user); } } @Test public void testInsertUser() throws Exception{ UserDao userDao=new UserDaoImpl(); User user=new User("HeadFirst","1", new SimpleDateFormat("yyyy-MM-dd").parse("2019-3-6"),"上海"); userDao.insertUser(user); } }

    5.2 官方推荐,接口动态代理

    5.2.1 动态代理Dao开发规则

    1. namespace必需是接口的全路径名 2. 接口的方法名必需与映射文件的sql id一致 3. 接口的输入参数必需与映射文件的parameterType类型一致 4. 接口的返回类型必须与映射文件的resultType类型一致

    5.2.2 动态代理Dao开发步骤

    1. 创建UserMapper.xml映射文件(把原来的user.xml复制按开发规则要求修改一下) 2. 创建UserMapper接口(把原来的UserDao.java复制按开发规则要求修改一下) 3. 加载UserMapper.xml

    4. 测试动态代理Dao

    package mybatis.test; import java.text.SimpleDateFormat; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import mybatis.mapper.UserMapper; import mybatis.pojo.User; import mybatis.utils.SqlSessionFactoryUtils; public class UserMapperTest { @Test public void testGetUserById() { SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(); //获取接口的代理实现类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.getUserById(30); System.out.println(user); sqlSession.close(); } @Test public void testGetUserByUserName() { SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(); //获取接口的代理实现类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> list=userMapper.getUserByUserName("小"); for(User user:list){ System.out.println(user); } sqlSession.close(); } @Test public void testInsertUser() throws Exception{ SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(true); //获取接口的代理实现类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.insertUser(new User("study","2", new SimpleDateFormat("yyyy-MM-dd").parse("2019-03-07"),"上海虹桥")); sqlSession.close(); } }

    6、SqlMapConf.xml配置

    6.1 properties

    6.1.1 属性核心文件配置

    <!-- 加载规则,首先加载标签内部属性,再加载外部文件,名称相同时,会替换相同名称的内容 也就是说先加载了root1,加载外部文件时用root替换了 --> <properties resource="jdbc.properties"> <property name="jdbc.username" value="root1"/> <property name="jdbc.password" value="123456"/> </properties> <!-- 和spring整合后 environments配置将废除 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments>

    6.1.2 jdbc.properties

    jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8 jdbc.username=root jdbc.password=123456

    6.2 typeAliases

    自定义别名:

    方式一: <typeAliases> <!-- 单个别名定义,且别名的使用不区分大小写 --> <typeAlias type="com.itheima.mybatis.pojo.User" alias="user"/> </typeAliases> 方式二: <typeAliases> <!-- 别名包扫描器:别名是类的全称,不区分大小写,适用于多个别名;推荐使用 --> <package name="com.itheima.mybatis.pojo"/> </typeAliases>

    6.3 mappers

    <!-- 加载映射文件 --> <mappers> <mapper resource="mybatis/user.xml" /> <!-- <mapper resource="mybatis/UserMapper.xml" /> --> <!-- 映射文件,class扫描器: 1、接口文件必须与映射文件同一目录下 2、接口文件名必须与映射文件的名称一致 (针对单个映射) --> <!-- <mapper class="mybatis.mapper.UserMapper"/> --> <!-- 映射文件包扫描:(推荐的方式:针对多个映射) 1、接口文件必须与映射文件同一目录下 2、接口文件名必须与映射文件的名称一致 --> <package name="mybatis.mapper"/> </mappers>
    最新回复(0)