MyBatis基础-增删改查

来源:互联网 发布:华为交换机 端口详解 编辑:程序博客网 时间:2024/05/22 02:28

          很多互联网公司放弃使用Hibernate, 改用MyBatis; 理由是MyBatis比较轻巧, 可以做SQL语句优化。PS: 想想DBA的工作吧, 大数量级的数据库操作需要专业的DBA做SQL语句优化。 Hibernate封装比较完善,导致它不够灵活。  我们需要的是减化数据库操作的编码量,对JDBC进行必要的封装即可。

         Hibernate和Mybatis都提供了缓存功能, 但实际项目开发中更多的是使用中间件如Redis来做缓存;Mybatis最大的优势是在Java代码里生成复杂的SQL语句,Hibernate做不到。

         MyBatis官方说明: http://www.mybatis.org/mybatis-3/zh/statement-builders.html

        百度百科上的介绍:https://baike.baidu.com/item/MyBatis/2824918?fr=aladdin

项目结构:


在pom.xml中添加junit,mybatis和log4j的maven仓库:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.brycegao.mybatis</groupId>    <artifactId>mybatis_demo</artifactId>    <version>1.0-SNAPSHOT</version>    <dependencies>        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis</artifactId>            <version>3.4.5</version>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.8.1</version>            <scope>test</scope>        </dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>6.0.6</version>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-api</artifactId>            <version>1.7.25</version>        </dependency>        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-log4j12</artifactId>            <version>1.7.25</version>        </dependency>        <dependency>            <groupId>log4j</groupId>            <artifactId>log4j</artifactId>            <version>1.2.17</version>        </dependency>    </dependencies></project>
   log4j默认会读取名为log4j.properties的文件。
  

    MyBatis是对JDBC的封装,建议不要用MyBatis创建表。 我先电脑上启动MySQL服务, 并创建一个名为mybatis的数据库和一个user表。


jdbc.properties文件里填写jdbc的各个属性:

jdbc.driverClassName=com.mysql.cj.jdbc.Driverjdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8&useSSL=truejdbc.username=rootjdbc.password=111111

设置mybatis-config.xml的属性(主要是jdbc和mapper标签):

<?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="jdbc.properties"/>    <!-- mybatis的各个配置项 -->    <settings>        <setting name="cacheEnabled" value="true"/>        <setting name="lazyLoadingEnabled" value="true"/>        <setting name="multipleResultSetsEnabled" value="true"/>        <setting name="useColumnLabel" value="true"/>        <setting name="useGeneratedKeys" value="false"/>        <setting name="autoMappingBehavior" value="PARTIAL"/>        <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>        <setting name="defaultExecutorType" value="SIMPLE"/>        <setting name="defaultStatementTimeout" value="25"/>        <setting name="defaultFetchSize" value="100"/>        <setting name="safeRowBoundsEnabled" value="false"/>        <setting name="mapUnderscoreToCamelCase" value="false"/>        <setting name="localCacheScope" value="SESSION"/>        <setting name="jdbcTypeForNull" value="OTHER"/>        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>    </settings>    <!-- 别名可以用在数据类型参数里,其实没啥用, 直接用原数据类型更直观! -->    <typeAliases>        <typeAlias alias="User" type="com.brycegao.mybatis.entity.User"/>    </typeAliases>    <environments default="development">        <environment id="development">            <transactionManager type="JDBC" />            <dataSource type="POOLED">                <property name="driver" value="${jdbc.driverClassName}" />                <property name="url" value="${jdbc.url}" />                <property name="username" value="${jdbc.username}" />                <property name="password" value="${jdbc.password}" />            </dataSource>        </environment>    </environments>    <mappers>        <!-- 跟Dao类对应的xml文件,编写SQL语句 -->        <mapper resource="mappers/user_mapper.xml" />    </mappers></configuration>

user-mapper.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"><!-- 一个interface对应一个mapper.xml文件 --><mapper namespace="com.brycegao.mybatis.dao.UserDao">    <!-- 查询语句 根据关键字查询记录, select id值必须跟UserDao方法名相同-->    <select id="findUserById" parameterType="Integer" resultType="com.brycegao.mybatis.entity.User">        select * from user where id=#{id}    </select>    <!-- 查询语句 注意:返回值类型是数组时,仍然使用item数据类型 -->    <select id="findUsersAll" resultType="com.brycegao.mybatis.entity.User">        select * from user    </select>    <!-- User是在mybatis-config.xml里声明的别名 -->    <!-- useGeneratedKeys表示是否自动生成主键值, keyProperty是主键列名 -->    <insert id="addUser" parameterType="User"            useGeneratedKeys="true" keyProperty="id" >        insert into `user`(name, age, address, job, idno, mobile)        values(#{name},#{age},#{address},#{job},#{idno},#{mobile})    </insert>    <!-- 更新记录 User是别名-->    <update id="updateUser" parameterType="User" flushCache="true">        update user set name=#{name}, age=#{age}, address=#{address}, job=#{job}, idno=#{idno}, mobile=#{mobile} where id=#{id}    </update>    <!-- 根据主键删除一条记录 SQL不区分大小写。 注意java代码的deleteUser函数参数跟SQL语句的变量相同-->    <delete id="deleteUser" parameterType="int">        DELETE FROM  user WHERE id=#{id}    </delete></mapper>

注意:

1、 select id要跟Java方法名相同, parameterType跟Java方法参数类型相同;

2、 namespace是Java中的接口类,Mybatis通过注解实现函数体;

3、 每个insert、update、select和delete标签对应一个sqlsession,可以单独配置超时、刷内存等等属性;


完整的junit测试类:注意在数据库操作完成后要释放SqlSession, 即调用其close方法,否则内存泄漏。 测试类在@Before里获取SqlSession实例, 在@Test里操作SqlSession实例, 在@After里释放SqlSession。

public class UserTest {    private final static Logger LOG = LoggerFactory.getLogger(UserTest.class);    private SqlSession session;    @Before    public void init() {        session = SqlSessionFactoryUtil.getSqlSession();    }    @Test    public void testQueryById() {        UserDao userDao = session.getMapper(UserDao.class);        User cur = userDao.findUserById(3);   //执行SQL语句:select * from user where id=3        if (cur != null) {            LOG.debug(cur.toString());        }        User curExt = userDao.findUserBydIdExt(3);        if (curExt != null) {            LOG.debug(curExt.toString());        }    }    @Test    public void testQueryAll() {        UserDao userDao = session.getMapper(UserDao.class);        List<User> list = userDao.findUsersAll();   //执行SQL语句:select * from user        if (list != null) {            System.out.println("记录总数:" + list.size());        }        List<User> all = userDao.getUsers();        if (all != null) {            System.out.println("记录总数:" + all.size());        }    }    @Test    public void testAddUser() {        UserDao userDao = session.getMapper(UserDao.class);        //第一种插入方法, 缺点是无返回值,不知道是否插入成功        /*        User user1 = new User();        user1.setAge(31);        user1.setName("张一");        user1.setAddress("天津");        userDao.addUser(user1);        session.commit();   //必须执行该语句!        */        //第二种插入方法,推荐使用! 有返回值,能判断是否插表成功        User user2 = new User();        user2.setAge(32);        user2.setName("张二");        user2.setAddress("天津");        //第一个参数是user_mapper.xml的namespace和id值拼起来        int resultCount = session.insert("com.brycegao.mybatis.dao.UserDao.addUser", user2); //如果插入成功,user2对象的id字段非0        System.out.printf("新插入记录id :%d ,插入记录数:%d ", user2.getId(), resultCount);  //获取插入对象的id        session.commit();   //数据有变化时必须同步到数据库, 否则只是刷新了缓存!    }    @Test    public void testUpdateUser() {        UserDao userDao = session.getMapper(UserDao.class);        //找到表中任意一条记录,然后修改它并回写数据库        User cur = userDao.findUserById(3);   //执行SQL语句:select * from user where id=3        System.out.println("testUpdateUser修改前:" + cur.getName());        cur.setAge(77);        //第一种方法        userDao.updateUser(cur);        session.commit();        //第二种方法        //int count = session.update("com.brycegao.mybatis.dao.UserDao.updateUser", cur);  //count表示更新的记录数        //session.commit();        //System.out.println("更新总数:" + count);        User curExt = userDao.findUserById(3);   //执行SQL语句:select * from user where id=3        System.out.println("testUpdateUser修改后:" + curExt.getName());    }    @Test    public void testDeleteUser() {        UserDao userDao = session.getMapper(UserDao.class);        //使用sql gui工具查看user表中的记录,随便挑一条记录        //第一种方法  无返回值!        userDao.deleteUser(6);        session.commit();        //第二种方法 count是成功删除的记录数        int count = session.delete("com.brycegao.mybatis.dao.UserDao.deleteUser", 6);        session.commit();    }    @After    public void deinit() {        session.close();    }}


在测试前先添加若干条数据:


分页查询的实现方法:

1、 使用SQL的limit关键字实现,通过区间限制即可实现分页查询功能;优点是不费内存,缺点是每次都要从数据库查询。

取前10条记录: select * from user limit 10    

取0~5条记录: select * from user limit 0,5

取5~10条记录: select * from user limit 5,10


2、 将表的内容缓存到内存, 每次从内存中读取; 一般是缓存到中间件Redis里, 优点是查询快,缺点是浪费内存。


在@Test函数体里点击鼠标左键, 然后选中Debug调试就可以了:

  


简要说一下Mybatis的动态SQL,即在Java代码里生成SQL语句; 支持生成增删改查语句, 下面以查询为例:

   1、 创建一个java文件, 每个函数都可以返还一个SQL语句字符串。 注意看Mybatis的语法很清晰,这也是Mybatis的一大优势!!! Mybatis在xml文件里可以实现相同功能,即根据条件判断生成复杂的SQL语句。

public class UserSqlBuilder {    //根据姓名查询记录    public String buildGetUsersByName(final String name) {        return new SQL() {{   //是2个大括号            SELECT("*");            FROM("user");            if (name != null) {  //支持条件判断                WHERE("name like #{name} || '%' ");    //#{...}跟@Param的值一致            }            ORDER_BY("id");        }}.toString();    }}

2、在UserDao.java里添加声明,

    //使用UserSqlBuilder.java的buildGetUsersByName方法    @SelectProvider(type= UserSqlBuilder.class, method="buildGetUsersByName")    List<User> getUserByName(String name);
3、使用:

        UserDao userDao = session.getMapper(UserDao.class);        List<User> list = userDao.getUserByName("张三");


demo代码:http://download.csdn.net/download/brycegao321/9956809