mabaties基础篇

来源:互联网 发布:郭德纲才学 知乎 编辑:程序博客网 时间:2024/06/16 13:13

一什么是Mybatis:

Mybatis是一个优秀的持久层框架。它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身。而不需要花费精力去注册驱动,创建连接connetion,创建statement,手动设置参数,结果集检索jdbc复杂的过程代码等复杂的过程代码。

Mybatis通过xml或注解的statement,Preparestatement,CallableStatement配置起来,并通过java对象和statement中的生成最终执行的sql语句,最后由mybaties框架执行sql并返回最终对象.

二 Mybatie,jdbc,hibernate的对比

 

2.1 Jdbc

public static void main(String[] args) {                 Connectionconnection = null;                 PreparedStatementpreparedStatement = null;                 ResultSetresultSet = null;                 try {                      Class.forName("com.mysql.jdbc.Driver");                      connection=  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");                      String sql = "select * from user whereusername = ?";                      preparedStatement= connection.prepareStatement(sql);                      preparedStatement.setString(1,"王五");                      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();                            }                      }                 }           }

Jdbc存在的问题与解决方案

一:频繁的开启或者关闭数据库连接,影响数据库性能。

二:代码中存在硬编码,数据库硬编码和SQL执行部门的硬编码。

解决上面的问题:通过xml的方式来配置。

 

2.2 Mybaties的技术特点:

1.        可以直接编写sql,并且对sql进行性能优化。

2.        学习门槛低,成本低,只要会sql就很快能够上手。

3.        直接编写sql,灵活性好,易于维护。

4.        对数据库无关性的支持不太好,如果数据库发生变更,要写多套代码。

5.        需要编写结果映射

2.3 Hibernate

1标准的orm框架,程序员不需要编写sql语句。

2 具有良好的数据库无关性,数据库发生改变的话无需变更配置,但是如果植入了sql的话,数据库变更就要进行变更。

3 学习门槛高,在or映射的时候既要考虑性能,也要权衡映射关系。

4 不能自主进行sql映射的优化。

 

Mybaties适合的场景:业务灵活多变的业务系统。

Hibernate适合的场景:业务固定的系统, 比如OA系统与CRM系统。

三 Mybaties工作原理图

1 mybaties配置文件:(mybaties全局配置文件与映射文件)

全局配置文件配置了数据源,事务等信息,映射文件配置了SQL执行相关的信息。

2 mybaties通过读取配置文件,构造出sqlsessionFactory,即构造出会话工厂。

3 通过sqlsessionFactory来创建会话sqlsession,并且通过sqlsession来直接连接数据库

4 sqlsession本身不能直接连接数据库,它是通过executor执行器来操作数据库的,executor本身有两个执行器,一个是普通的执行器,一个是默认的执行器。这个过程是同过一个mappper代理来完成的。

5 executor把要执行的sql信息封装到了一个底层mappedStatement对象中,该对象包括sql语句,输入参数映射信息,输出结果的映射信息。

四 全局配置文件常见配置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><environments default="development"><environment id="development"><transactionManager type="JDBC"></transactionManager><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><typeAliases><!-- 单个定义别名 --><typeAlias type="cn.itcast.mybatis.po.User" alias="user"/><!-- 批量定义别名(推荐) --><!-- [name]:指定批量定义别名的类包,别名为类名(首字母大小写都可) --><package name="cn.itcast.mybatis.po"/></typeAliases><mappers><mapper resource="sqlmap/User.xml"/></mappers></configuration>

五 mybaties模拟基本的增删改查

 

5.1 模拟需求: 根据用户id查询用户信息

在User.xml中添加以下代码:

<mapper namespace="test">    <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">       SELECT * FROMUSER WHERE id = #{id}    </select></mapper>

Namespace:命名空间,它的作用是对SQL进行分类化管理,是SQL的隔离标识,如果是使用mapper代理做开发它有很大的作用。

Id:statement的id,命名空间内标签的唯一标识。

resultType:查询出单条结果集,所对应的java类型。

#{}: 标识一个占位符?

#{id}:表示该占位符待接收参数的名称为id,简单类型#{}里面的参数名称可以是任意定义的。

 

5.2 模拟需求: 根据用户名称模糊查询用户信息

User.xml中配置如下

<mapper namespace="test">   <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">       SELECT * FROMUSER WHERE id = #{id}   </select></mapper>

${} 表示拼接sql字符串。

${value} 表示要拼接的是简单类型的参数。

1:如果参数为简单类型时,里面的参数必须为value

2:${} 会引起sql注入,一般不推荐使用,但是有些场景必须使用${} 比如order by ${column}

 

5.3 模拟需求: 添加用户信息

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">    INSERT INTOUSER(username,sex,birthday,address) VALUES (#{username},#{sex},#{birthday},#{address})</insert>

#{} 表示占位符,就相当于原生sql预编译时的?,最终将会由executor进行调用jdbc的欲编译语句进行替换。

 

5.4 需求模拟: 删除用户

<delete id="deleteUser" parameterType="int">    DELETE FROM USERWHERE id= #{id}</delete>

 

5.5 需求模拟:修改用户

<delete id="deleteUser" parameterType="int">    DELETE FROM USERWHERE id= #{id}</delete>


六 mybaties主键生策略

 

6.1 自增主键的生成策略,以mysql为例来描述主键生成策略。

insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"><selectKey keyProperty="id" resultType="int" order="AFTER">SELECT LAST_INSERT_ID()</selectKey>INSERT INTO USER(username,sex,birthday,address) VALUES (#{username},#{sex},#{birthday},#{address})</insert>

SelectKey标签:通过selectkey查询来生成主键。

KeyProperty:指定存放生成主键的属性。

resultType 主键所对应的java类型

order 制定该查询与句相对于insert语句的执行顺序,如果是自增主键应该在插入之前先执行,生成id,如果是主键回调,则应该放在插入之后执行。

6.2 主键生成策略之uuid()

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">    <selectKey keyProperty="id" resultType="string"order="BEFORE">       SELECT UUID()    </selectKey>    INSERT INTOUSER(id,username,sex,birthday,address) VALUES (#{id},#{username},#{sex},#{birthday},#{address})</insert>

再插入之前先调用mysql的函数生成一个唯一的UUID,UUID生成的字符串是35位的。

6.3主键返回之oracle序列:

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">    <selectKey keyProperty="id" resultType="int"order="BEFORE">       SELECT user_seq.nextval()FROM dual    </selectKey>    INSERT INTOUSER(id,username,sex,birthday,address) VALUES (#{id},#{username},#{sex},#{birthday},#{address})</insert>


七 关键点总结

parameterType指定输入参数的java类型,可以填写别名或Java类的全限定名。

resultType指定输出结果的java类型,可以填写别名或Java类的全限定名。

 

 

#{}和${}

#{}:相当于预处理中的占位符?。

#{}里面的参数表示接收java输入参数的名称。

#{}可以接受HashMap、简单类型、POJO类型的参数。

当接受简单类型的参数时,#{}里面可以是value,也可以是其他。

#{}可以防止SQL注入。

${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。

${}会引起SQL注入,所以要谨慎使用。

${}可以接受HashMap、简单类型、POJO类型的参数。

当接受简单类型的参数时,${}里面只能是value。


八 Mybaties持久层开发方式

 

7.1 方式一:dao方式开发

操作步骤:

1 编写实体类

2 编写实体类xml映射文件

3 配置全局xml文件

4 加载全局文件,构建sqlsessionfactory

5 通过sqlsessionfactory创建sqlsession

6 通过sqlsession调用远程的select等方法

 

开发dao接口:

public interface UserDao {public User findUserById(int id); public List<User> findUsersByName(String username);public void insertUser(User user);}


SqlSessionFactoryBuilder

它的作用只是通过配置文件创建SqlSessionFactory,所以只要创建出SqlSessionFactory,它就可以销毁了。所以说,它的生命周期是在方法之内。

 

SqlSessionFactory

它的作用是创建SqlSession的工厂,工厂一旦创建,除非应用停掉,不要销毁。

所以说它的生命周期是在应用范围内。这里可以通过单例模式来管理它。

在mybatis整合spring之后,最好的处理方式是把SqlSessionFactory交由spring来做单例管理。

 

SqlSession

SqlSession是一个面向用户(程序员)的接口,它的默认实现是DefaultSqlSession。

Mybatis是通过SqlSession来操作数据库的。SqlSession中不仅包含要处理的SQL信息,还包括一些数据信息,所以说它是线程不安全的,因此它最佳的生命周期范围是在方法体之内。

public class UserDaoImpl implements UserDao {private SqlSessionFactory sqlSessionFactory;public UserDaoImpl(SqlSessionFactory sqlSessionFactory){this.sqlSessionFactory = sqlSessionFactory;}@Overridepublic User findUserById(int id) {SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession.selectOne("test.findUserById", id);}@Overridepublic List<User> findUsersByName(String username) {SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession.selectList("test.findUsersByName", username);}@Overridepublic void insertUser(User user) {SqlSession sqlSession = sqlSessionFactory.openSession();sqlSession.insert("test.insertUser", user);}}


测试方法:

public class UserDaoTest {private SqlSessionFactory sqlSessionFactory;@Beforepublic void setUp() throws Exception { String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindUserById() { UserDao userDao = new UserDaoImpl(sqlSessionFactory); User user = userDao.findUserById(1);System.out.println(user);}@Testpublic void testFindUsersByName() { UserDao userDao = new UserDaoImpl(sqlSessionFactory); List<User> list = userDao.findUsersByName("小明");System.out.println(list);}@Testpublic void testInsertUser() {UserDao userDao = new UserDaoImpl(sqlSessionFactory); User user = new User();user.setUsername("东哥3");user.setAddress("清河宝盛西里3"); userDao.insertUser(user);System.out.println(user.getId());}}


Dao开发方式存在的一些问题:

1 存在一些模板代码比如创建sqlsessionfactory,创建sqlsession,关闭sqlsession。

2 存在一些硬编码,比如statement,参数之类的。

 

7.2 方式二 mapper方式开发

Mapper的开发规范:

1 mapper接口的全限定名要与xml配置文件中的namespace相同。

2 mapper接口中的方法名称要和statement中的id一致。

3 mapper接口中的参数只能有一个,且类型要与statement中是parametertype的类型一致。

4 mapper接口的返回值类型要和statement中的resulttype与resultmap一致。

 

操作:

根据需求创建po类

编写全局配置文件

根据需求编写映射文件

加载映射文件

编写mapper接口

编写测试代码

 

UserMapper.xml文件的编写:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"    "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- namespace:此时用mapper代理方式,它的值必须等于对应mapper接口的全限定名  --><mapper namespace="cn.itcast.mybatis.mapper.UserMapper"><!-- 根据用户ID,查询用户信息 --><!-- [id]:statement的id,要求在命名空间内唯一  [parameterType]:入参的java类型,可是是简单类型、POJO、HashMap[resultType]:查询出的单条结果集对应的java类型[#{}]: 表示一个占位符?[#{id}]:表示该占位符待接收参数的名称为id。注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义 --><select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">SELECT * FROM USER WHERE id = #{id}</select><!-- 根据用户名称模糊查询用户信息列表 --><!-- [${}]:表示拼接SQL字符串,即不加解释的原样输出 [${value}]:表示要拼接的是简单类型参数。1、如果参数为简单类型时,${}里面的参数名称必须为value 2、${}会引起SQL注入,一般情况下不推荐使用。但是有些场景必须使用${},比如order by ${colname}--><select id="findUsersByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">SELECT * FROM USER WHERE username LIKE '%${value}%'</select><!-- 添加用户之自增主键返回(selectKey方式) --><!—[selectKey标签]:通过select查询来生成主键[keyProperty]:指定存放生成主键的属性[resultType]:生成主键所对应的Java类型[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句,此时选用AFTER[last_insert_id]:MySQL的函数,要配合insert语句一起使用--><insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"><selectKey keyProperty="id" resultType="int" order="AFTER">SELECT LAST_INSERT_ID()</selectKey>INSERT INTO USER(username,sex,birthday,address) VALUES (#{username},#{sex},#{birthday},#{address})</insert></mapper>


在全局配置文件中配置mapper的映射

<mappers><mapper resource="sqlmap/User.xml"/><mapper resource="mapper/UserMapper.xml"/></mappers>

编写mapper接口

publicinterface UserMapper {         publicUser findUserById(int id);         publicList<User> findUsersByName(String username);         publicvoid insertUser(User user);}

测试代码:

public class UserMapperTest {// 声明全局的SqlSessionFactoryprivate SqlSessionFactory sqlSessionFactory;@Beforepublic void setUp() throws Exception { String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindUserById() {SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.findUserById(1);System.out.println(user);sqlSession.close();}@Testpublic void testFindUsersByName() {SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> list = userMapper.findUsersByName("小明");System.out.println(list);sqlSession.close();}@Testpublic void testInsertUser() {SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = new User();user.setUsername("东哥4");user.setAddress("清河宝盛西里4"); userMapper.insertUser(user);System.out.println(user.getId());sqlSession.commit();sqlSession.close();}}


 




原创粉丝点击