Mybatis基础知识(1)

来源:互联网 发布:矩阵乘法公式 编辑:程序博客网 时间:2024/05/21 22:25

1、原生态JDBC

1.1、原生态jdbc程序:

package lsq.mybatis.jdbc;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;/** * 基本的jdbc程序 * @author Daniel Li * */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/mybatisday1", "root", "root");//定义sql语句,?表示占位符String sql = "select * from user where username = ?";//获取预处理statementpreparedStatement = 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、原生态jdbc问题总结

      1)数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能。

            设想:使用数据库连接池管理数据库连接。

      2)将sql语句硬编码到Java代码中,如果sql语句修改,需要重新编译Java代码,不利于系统维护。

            设想:将sql语句配置在xml配置文件中,即使sql变化,也不需要对java代码进行重新编译。

      3)向preparedStatement中设置参数,对占位符位置和设置参数值,硬编码在java代码中,不利于系统维护。

            设想:将sql语句及占位符号和参数全部配置在xml中。

      4)从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。

            设想:将查询的结果集,自动映射成java对象。

2、Mybatis框架

      2.1、Mybatis是什么?

      Mybatis是一个持久层框架,是Apache下的顶级项目。

      Mybatis让程序员将主要精力放在sql上,通过Mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要的sql语句。

      Mybatis可以将向preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)

      2.3、Mybatis基础架构

      

      基础支持层:Mybatis的一些运行环境(数据源、事务、基本配置加载、缓存处理等)

      数据处理层:Mybatis负责接收参数、解析参数,并且执行返回映射结果集。

      接口层:Mybatis提供操作数据库的一些接口,供程序员使用。

      2.2、Mybatis框架运行流程


      加载全局配置文件:加载数据源、事务,用来操作数据库;

      获取sqlSessionFactory:用来生成sqlSession,其中sqlSessionFactory是线程安全的(不共享)

      sqlSession:由sqlSessionFactory生产,sqlSession中提供了一系列操作数据库的接口,程序员通过调用sqlSession提供的接口来操作数据。

3、入门程序

3.1、创建全局配置文件SQLMapConfig.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- mybatis初始化环境的配置,可以配置多个环境 spring tools suit --><environments default="development"><!-- 配置当前自己的运行环境 --><environment id="development"><!-- jdbc事务,Mybatis负责管理 --><transactionManager type="JDBC" /><!-- jdbc数据源,Mybatis进行管理 --><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver" /><property name="url"value="jdbc:mysql://localhost:3306/mybatis_day01?characterEncoding=utf-8" /><property name="username" value="root" /><property name="password" value="root" /></dataSource></environment></environments><mappers><mapper resource="sqlMap/UserMapper.xml" /></mappers></configuration>
3.2、创建映射文件

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- mapper:表示mybatis的映射文件的开始,namespace:命名空间,用来隔离sql语句(mapper文件的唯一标示),可以随意命名注意:namespace在接口代理开发中,有特殊含义,不能自定义命名 --><mapper namespace="test"><!-- select:mybatis提供的用来查询的标签;id:mybatis加载映射文件之后,把映射文件封装成一个对象,mappedStatement;查询语句被封装成一个Statement对象,id就是Statement的唯一标识;resultType:返回值类型,返回集合,不管返回的是单个对象还是集合,都是一样的返回值类型 --><select id="findAllUser" resultType="lsq.study.domain.User">select * from user</select></mapper>
3.3、编写测试方法

package lsq.study.mybatis.test;import java.io.InputStream;import java.util.List;import lsq.study.domain.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Test;public class Main1 {    @Test    public void findAllUser() throws Exception{        //1、加载全局配置文件        String resource = "sqlMapConfig.xml";        InputStream inputStream = Resources.getResourceAsStream(resource);                //2、获取sqlSessionFactory        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);                //3、使用sqlSessionFactory获取sqlSession        SqlSession sqlSession = sqlSessionFactory.openSession();                //4、使用sqlSession操作数据库        List<User> list = sqlSession.selectList("test.findAllUser");                System.out.println(list);    }    }
3.4、根据用户id进行查询

创建映射文件

<!-- 根据用户id进行查询id:statement的唯一标识;parameterType:传递参数类型resultType:返回值类型,根据id查询,返回的是单个对象,和上边查询集合的写法一样#{}:占位符,Mybatis会解析#{}为占位符。如果传递的参数是基本类型:int,string,long等等,#{}里面可以任意写。 --><select id="findUserById" parameterType="int" resultType="lsq.study.domain.User">select * from user where id = #{id}</select>
测试方法

 @Test    public void findUserById(){        SqlSession sqlSession = sqlSessionFactory.openSession();                User user = sqlSession.selectOne("test.findUserById", 10);                System.out.println(user);    }
3.5、根据用户名进行模糊查询
映射文件

<!-- 根据用户名模糊查询#{}:占位符,如果传递参数是非字符类型,获取参数是原样获取,如果是字符串,#{}获取时会自动添加一个引号。${}:拼接sql语句,不管传递参数是什么类型,都是原样获取如果传递是基本类型参数,int,string等,${}只能写value;如果传递参数是对象,#{}${}都是ognl表达式来获取,对象导航语言 属性.属性.属性 --><select id="findUserByUsername" parameterType="string" resultType="lsq.study.domain.User">select * from user where username like '%${value}%'</select>
测试方法

    @Test    public void findUserByUsername(){        SqlSession sqlSession = sqlSessionFactory.openSession();        List<User> list = sqlSession.selectList("test.findUserByUsername", "张");        System.out.println(list);    }
3.6、根据用户id进行删除

映射文件

<!-- 根据用户id进行删除 --><delete id="deleteUserById" parameterType="int">delete from user where id = #{id}</delete>
测试方法

    @Test    public void deleteUserById(){        SqlSession sqlSession = sqlSessionFactory.openSession();        sqlSession.delete("test.deleteUserById", 26);        sqlSession.commit();        sqlSession.close();    }
3.7、根据用户id进行更新

映射文件

<!-- 根据id更新用户parameterType:传递对象参数,使用ognl表达式进行获取。 --><update id="updateUserById" parameterType="lsq.study.domain.User">update user set username=#{username},sex=#{sex},birthday=#{birthday} where id=#{id}</update>
测试方法

    @Test    public void updateUserById(){        SqlSession sqlSession = sqlSessionFactory.openSession();        User user = new User();        user.setAddress("上海市浦东新区成山路475弄45号401室");        user.setBirthday(new Date());        user.setUsername("马布里");        user.setSex("男");        user.setId(25);        sqlSession.update("test.updateUserById", user);                sqlSession.commit();        sqlSession.close();    }
3.8、添加用户

映射文件

<!-- 添加用户Mybatis返回主键:使用selectKey标签。keyProperty,表示返回的对应JavaBean里边的属性(id);order:由于MySQL自增主键是在insert语句执行之后生成的,所以要使用AFTER; --><insert id="insertUser" parameterType="lsq.study.domain.User" useGeneratedKeys="true" keyProperty="id"><!-- 第一种方式 --><!-- <selectKey keyProperty="id" order="AFTER" resultType="int">select last_insert_id()</selectKey> --><!-- 第二种方式返回主键:直接在insert标签中配置useGeneratedKeys/keyProperty -->insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address})</insert>
测试代码

    /*     * Hibernate中级联保存外键自动生成:     * user-order     * user.setOrders(orders)     * session.save(user)     *      * 但是在Mybatis中外键需要我们自己维护     *      */    @Test    public void insertUser(){        SqlSession sqlSession = sqlSessionFactory.openSession();        User user = new User();        user.setAddress("上海市浦东新区成山路475弄45号401室");        user.setBirthday(new Date());        user.setUsername("steven");        user.setSex("女");                sqlSession.insert("test.insertUser", user);                System.out.println(user.getId()+"@@@@@@@@@@@@@@@@@");        sqlSession.commit();        sqlSession.close();    }
3.9、Mybatis返回主键

a、返回int类型自增主键

第一种方式:

第二种方式:

b、返回uuid主键

c、返回oracle

总结:

1、parameterType

      基本类型

      对象

2、ResultType

      基本类型

      集合、对象(都写对象类型)

3、#$

      #{}:占位符,如果传递参数是基本类型,#{}括号中可以是任意字符。

               如果传递的是pojo对象,使用ognl表达式进行获取:属性.属性

               如果传递的是字符类型,#{}会自动添加引号;

               如果传递的是非字符类型,#{}会原样获取。

      ${}:拼接sql语句,不管传递的是字符类型还是非字符类型都会原样获取。

               如果传递的是基本类型,${}括号中只能写value。

4、selectList和selectOne

      Mybatis提供的底层查询接口方法,理论上来说不能混合使用。在接口开发当中尤其不能进行混合使用。

4、Mybatis的dao开发

4.1、Mybatis的dao的普通开发模式

      自己定义接口和接口实现类

      接口代码:

package lsq.study.dao;import java.util.List;import lsq.study.domain.User;public interface UserDao {    public List<User> findAllUser();    public User findUserById(Integer id);    public List<User> findUserByUsername(String username);}
      实现类:

package lsq.study.dao.impl;import java.util.List;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import lsq.study.dao.UserDao;import lsq.study.domain.User;public class UserDaoImpl implements UserDao {    private SqlSessionFactory sqlSessionFactory;        String ns = "test.";         public UserDaoImpl(SqlSessionFactory sqlSessionFactory){        this.sqlSessionFactory = sqlSessionFactory;    }        @Override    public List<User> findAllUser() {        SqlSession sqlSession = sqlSessionFactory.openSession();        List<User> list = sqlSession.selectList(ns + "findAllUser");        return list;    }    @Override    public User findUserById(Integer id) {        SqlSession sqlSession = sqlSessionFactory.openSession();        User user = sqlSession.selectOne(ns + "findUserById", id);        return user;    }    @Override    public List<User> findUserByUsername(String username) {        SqlSession sqlSession = sqlSessionFactory.openSession();        List<User> list = sqlSession.selectList(ns + "findUserByUsername", username);        return list;    }}
      测试方法

    @Test    public void findAllUser01(){        UserDao userDao = new UserDaoImpl(sqlSessionFactory);        List<User> list = userDao.findAllUser();        System.out.println(list);    }        @Test    public void findUserById01(){        UserDao userDao = new UserDaoImpl(sqlSessionFactory);        User user = userDao.findUserById(25);        System.out.println(user);    }        @Test    public void findUserByUsername01(){        UserDao userDao = new UserDaoImpl(sqlSessionFactory);        List<User> list = userDao.findUserByUsername("兰");        System.out.println(list);    }

4.2、Mybatis的接口代理开发模式

      只需要编写接口即可:

package lsq.study.dao;import java.util.List;import lsq.study.domain.User;public interface UserDao {    public List<User> findAllUser();    public User findUserById(Integer id);    public List<User> findUserByUsername(String username);}
      接口代码开发需要遵循几个规范:

      ☆:方法名必须和映射文件Statement的ID一致

      ☆:Namespace的名字必须是接口的全类路径名

      ☆:statement传递参数的类型必须和接口参数类型一致

      ☆:接口返回值类型必须和statement的返回值类型一致,Mybatis底层会根据接口返回值类型判断到底使用selectOne和selectList

      注意:这里直接使用resource引用进行接口开发:

      

5、Mybatis和Hibernate的区别

      Hibernate优点:Hibernate也是一个对JDBC封装的持久层框架。

      ☆:Hibernate是一个ORM框架,面向对象开发,不用自己写sql

      ☆:由于使用面向对象开发,如果进行数据库迁移,只需要修改方言

      缺点:

      ☆:由于使用面向对象开发,不能开发特别复杂的业务项目。

      ☆:表的关系维护,Hibernate自己维护表关系,对我们是透明的,不容易进行优化。Hibernate表关系维护特别复杂。

      ☆:由于使用hql,先把hql转化成sql再进行执行,执行效率变低。生成的sql语句格式不容易维护。

      适合需求基本不变的项目,企业当中的ERP、CRM


      Mybatis框架:

      Mybatis使用纯sql进行开发,程序员只需要集中精力在sql上面就可以,方便对sql进行优化。适合需求变化特别快的项目。互联网项目。


6、Mybatis全局配置文件sqlMapConfig

      基本配置内容

      SqlMapConfig.xml中的配置内容和顺序如下:

      properties(属性)

      settings(全局配置参数)

      typeAliases(类型别名)

      typeHandlers(类型处理器)

      objectFactory(对象工厂)

      plugins(插件)

      environments(环境集合属性对象)

            environment(环境子属性对象)

                  transactionManager(事务管理)

                  dataSource(数据源)

      mappers(映射器)


6.1、properties

      Mybatis资源引用标签,用来引入外部资源文件

6.2、typeAliases(别名):Mybatis提供的配置别名的标签

     6.2.1 定义单个别名

      添加了别名之后,映射文件中的变化

      之前

      之后


      6.2.2 批量定义别名

      该包下的所有类都会被定义别名,别名即为该类类名。

            

      Mybatis默认支持别名

      

6.3、typeHandlers(类型处理器)

      通常Mybatis的typeHandlers完成jdbc类型和java类型的转换。

      通常情况下,Mybatis提供的类型处理器满足日常的需求,不需要自定义。

      

6.4、Mappers(映射器)

      第一种引入映射文件

      

      第二种引入映射文件

      

      批量扫面接口

      

7、ParameterType(Mybatis输入参数)

      基本类型、pojo、map

      7.1、传递POJO

      ☆:需求:

      查询参数特别复杂,涉及非持久化的参数

      查询用户性别为男,姓马用户

      如果业务参数类型特别复杂,使用包装类型pojo进行传递参数

      

      

      

      接口方法:  

package lsq.study.dao;import java.util.List;import lsq.study.domain.QueryUserVo;import lsq.study.domain.User;public interface UserDao {    public List<User> findAllUser();    public User findUserById(Integer id);    public List<User> findUserByUsername(String username);    public List<User> findUserByUsernameAndSex(QueryUserVo vo);    }

      映射文件编写:

      
      测试方法

    @Test    public void findUserByUsernameAndSex(){        SqlSession sqlSession = sqlSessionFactory.openSession();        UserDao userDao = sqlSession.getMapper(UserDao.class);        QueryUserVo queryUserVo = new QueryUserVo();        UserCustom userCustom = new UserCustom();        userCustom.setSex("男");        userCustom.setUsername("马");        queryUserVo.setUserCustom(userCustom);                List<User> list = userDao.findUserByUsernameAndSex(queryUserVo);        System.out.println(list);    }


      7.2、传递map

      需求同上。

      映射文件

      
      接口方法

      
      测试方法

    @Test    public void findUserByMap(){        SqlSession sqlSession = sqlSessionFactory.openSession();        UserDao userDao = sqlSession.getMapper(UserDao.class);        Map<String, Object> map = new HashMap<String, Object>();        map.put("sex", "男");        map.put("username", "马");        List<User> list = userDao.findUserByMap(map);        System.out.println(list);    }


8、ResultType

      基本类型、pojo(返回对象或者返回集合都是写全类路径名,或者别名)

      8.1、pojo类型

      ☆:需求

      查询满足条件的总记录和查询满足条件的总记录数

      查询性别为女并且姓兰

      查询满足条件总记录数:

      映射文件

      
      接口方法:

      
      测试方法

    @Test    public void findUserByUsernameAndSex(){        SqlSession sqlSession = sqlSessionFactory.openSession();        UserDao userDao = sqlSession.getMapper(UserDao.class);        QueryUserVo queryUserVo = new QueryUserVo();        UserCustom userCustom = new UserCustom();        userCustom.setSex("女");        userCustom.setUsername("兰");        queryUserVo.setUserCustom(userCustom);                List<User> list = userDao.findUserByUsernameAndSex(queryUserVo);                int count = userDao.findUserByUsernameAndSexCount(queryUserVo);        System.out.println(count + "@@@@@@@@@@@@@");        System.out.println(list);    }

      8.2、map类型

      开发中,如果返回的是基本类型,使用ResultType;如果返回的是对象,基本上使用ResultMap。

      ResultMap高级映射:

      映射文件:

      
      测试方法

    @Test    public void findAllUser(){        SqlSession sqlSession = sqlSessionFactory.openSession();        UserDao userDao = sqlSession.getMapper(UserDao.class);        List<User> list = userDao.findAllUser();        System.out.println(list);    }
      测试结果

     

9、动态sql

      9.1、使用动态sql可以对sql语句进行灵活的封装、拼接。

      映射文件
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="lsq.study.dao.UserDao"><resultMap type="user" id="BaseResultMapRm"><id column="id" property="id"/><result column="username" property="username"/><result column="birthday" property="birthday"/><result column="sex" property="sex"/><result column="address" property="address"/></resultMap><!-- where:Mybatis中提供的条件查询标签if:Mybatis提供的条件判断标签 --><select id="findUserByUsernameAndSex" parameterType="queryUserVo" resultMap="BaseResultMapRm">select * from user <where><if test="userCustom.sex != null and userCustom.sex!=''">and sex=#{userCustom.sex}</if><if test="userCustom.username!=null and userCustom.username!=''">and username like '%${userCustom.username}%'</if></where></select><select id="findUserByUsernameAndSexCount" parameterType="queryUserVo" resultType="int">select COUNT(1) from user<where><if test="userCustom.sex != null and userCustom.sex!=''">and sex=#{userCustom.sex}</if><if test="userCustom.username!=null and userCustom.username!=''">and username like '%${userCustom.username}%'</if></where></select></mapper>
      测试代码
    @Test    public void findUserByUsernameAndSex(){        SqlSession sqlSession = sqlSessionFactory.openSession();        UserDao userDao = sqlSession.getMapper(UserDao.class);        QueryUserVo queryUserVo = new QueryUserVo();        UserCustom userCustom = new UserCustom();        userCustom.setSex("男");        userCustom.setUsername("马");        queryUserVo.setUserCustom(userCustom);                List<User> list = userDao.findUserByUsernameAndSex(queryUserVo);        int count = userDao.findUserByUsernameAndSexCount(queryUserVo);                System.out.println(count+"############################");        System.out.println(list);    }

      9.2、sql片段

      定义sql片段(抽取公共的sql语句)
      
       引入sql片段:
<resultMap type="user" id="BaseResultMapRm"><id column="id" property="id" /><result column="username" property="username" /><result column="birthday" property="birthday" /><result column="sex" property="sex" /><result column="address" property="address" /></resultMap><!-- 定义sql片段,抽取公共的sql语句sql:Mybatis提供的用来定义sql片段的标签;id:sql片段的唯一标识,可以定义多个sql片段 --><sql id="query_sql"><if test="userCustom.sex != null and userCustom.sex!=''">and sex=#{userCustom.sex}</if><if test="userCustom.username!=null and userCustom.username!=''">and username like '%${userCustom.username}%'</if></sql><!-- where:Mybatis中提供的条件查询标签 if:Mybatis提供的条件判断标签 --><select id="findUserByUsernameAndSex" parameterType="queryUserVo"resultMap="BaseResultMapRm">select * from user<where><include refid="query_sql"></include></where></select><select id="findUserByUsernameAndSexCount" parameterType="queryUserVo"resultType="int">select COUNT(1) from user<where><include refid="query_sql"></include></where></select>
9.3、Foreach
      如果传递参数是集合和数组,使用foreach进行循环解析参数

      SELECT * FROM USER WHERE id=1 OR id=23 OR id=33

      SELECT * FROM USER WHERE id IN(1,23,33)

      传递数组和集合都可以

      映射文件
      
      测试代码:
    @Test    public void findUserByIds(){        SqlSession sqlSession = sqlSessionFactory.openSession();        UserDao userDao = sqlSession.getMapper(UserDao.class);        List<Integer> ids = new ArrayList<Integer>();        ids.add(1);        ids.add(25);        ids.add(29);        QueryUserVo queryUserVo = new QueryUserVo();        queryUserVo.setIds(ids);                List<User> list = userDao.findUserByIds(queryUserVo);        System.out.println(list);            }
      测试结果:
      

     第二种:
      映射方法
     
      测试代码
    @Test    public void findUserByIdsIN(){        SqlSession sqlSession = sqlSessionFactory.openSession();        UserDao userDao = sqlSession.getMapper(UserDao.class);        List<Integer> ids = new ArrayList<Integer>();        ids.add(1);        ids.add(25);        ids.add(29);        QueryUserVo queryUserVo = new QueryUserVo();        queryUserVo.setIds(ids);                List<User> list = userDao.findUserByIdsIN(queryUserVo);        System.out.println(list);            }
      测试结果:
      













0 0
原创粉丝点击