开源*持久层框架——mybatis(ibatis)——day01

mybatis-day01

    1.对原生态jdbc程序中的问题总结

        1.1环境

            java环境:jdk

            eclipse:indigo

            mysql:xx

mybatis x.x.x

1.2jdbc程序

            使用jdbc查询mysql数据中用户表的记录

1.4问题总结

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

            解决方案:使用数据库连接池管理数据库连接。

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

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

            解决方案:将sql语句及占位符和参数全部配置在xml中。

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

            解决方案:将查询的结果集,自动映射成java对象

2.mybatis框架

        2.1mybatis是什么?

            mybatis是一个持久层的框架,是apache下的*项目。

            mybatis托管到Google code,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)

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

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

        

        2.2mybatis框架图示

3.入门程序

        3.1需求

            根据用户id(主键)查询用户信息

            更加用户名称模糊查询用户信息

            添加用户

            删除用户

            更新用户

3.2环境

            java环境:jdk

            eclipse:indigo

            mysql:x.x

mybatis运行环境(jar包)

            从http://github.com/mybatis/mybatis-3/releases下载,

在下载的文件中:

                lib:依赖包

                mybatis-x.x.x.jar:核心包

                mybatis-x.x.x.pdf:操作指南

加入mysql的驱动包

3.3log4j.properties

            # Global logging configuration

            #\u5728\u5f00\u53d1\u73af\u5883\u4e0b\u65e5\u5fd7\u7ea7\u522b\u8981\u8bbe\u7f6e\u6210DEBUG\uff0c\u751f\u4ea7\u73af\u5883\u8bbe\u7f6e\u6210info\u6216error

            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.4工程结构

3.5SqlMapConfig.xml

            配置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/sql_mybatis?characterEncoding=utf-8" />

                            <property name="username" value="root" />

                            <property name="password" value="123456" />

                        </dataSource>

                    </environment>

                </environments>

<!-- 加载映射文件 -->

                <mappers>

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

                </mappers>

</configuration>

3.6根据用户id(主键)查询用户信息

            3.6.1创建po类

            public class User {

                // 属性名和数据库表的字段对应

                private int id;

                private String username;// 用户姓名

                private String sex;// 性别

                private Date birthday;// 生日

                private String address;// 地址

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语句 -->

                            <!-- 需求:通过di查询用户表的记录 -->

                            <!-- 通过select执行数据库查询

                            id:标识映射文件中的sql,称为statement的id

                            将sql语句封装到mappedStatement对象中,所以将id称为statement的id

                            

                            parameterType:指定输入参数的类型,这里指定int型

                            

                            #{}表示一个占位符号

                            

                            #{id}:其中的id表示接收输入的参数,参数名称就是id,如果输入参数是简单类型,#{}中的参数可以任意,可以value或其他名称

                            

                            resultType:指定输出结果所映射的java对象类型,select指定resultType表示将单条记录映射成java对象。

                             -->

                            <select id="findUserById" parameterType="int" resultType="com.changemax.mybatis.po.User">

                                SELECT * FROM user WHERE id = #{id}

                            </select>

                            

                            

                            <!-- 根据用户名称模糊查询用户信息,可能返回多条

                                resultType:指定就是单条记录所映射的java对象类型 

                                ${}:表示拼接sql串,将接受到的参数的内容不加任何修饰拼接在sql中。

                                使用${}容易出现sql注入

                                ${value}:表示接收输入参数的内容,如果传入类型是简单类型,${}中只能使用value-->

                            <select id="findUserByLikeName" parameterType="java.lang.String" resultType="com.changemax.mybatis.po.User">

                                SELECT * FROM user WHERE username LIKE  '%${value}%'

                            </select>

                        </mapper>

3.6.3在SqlMapConfig.xml加载映射文件

                在sqlMapConfig.xml中加载User.xml

                <!-- 加载映射文件 -->

                <mappers>

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

                </mappers>

3.6.4程序编写

                // 根据id查询用户信息,得到一条记录结果

                @Test

                public void findUserByIdTest() throws IOException {

SqlSession session = null;

try {

// mybatis配置文件

                        String resource = "SqlMapConfig.xml";

// 得到配置文件流

                        InputStream inputStream = Resources.getResourceAsStream(resource);

// 创建会话工厂,要想build中传入mybatis配置信息

                        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

// 通过工厂得到SqlSession

                        session = factory.openSession();

// 通过SqlSession操作数据库

                        // 第一个参数:映射文件中statement种的id,等于=namespace+"."+statement的id

                        // 第二个参数:指定和映射文件中所匹配的paramenterType类型的参数

                        // session.selectOne结果是与映射文件中所匹配的resultType类型的对象

                        User user = session.selectOne("test.findUserById", 1);

System.out.println(user);

                    } catch (Exception e) {

                        // TODO: handle exception

                    } finally {

                        if (session != null) {

                            // 释放资源

                            session.close();

                        }

                    }

}

3.7根据用户名称模糊查询用户信息

            3.7.1映射文件

                使用User.xml,添加根据用户名模糊查询用户信息的sql语句。

<!-- 根据用户名称模糊查询用户信息,可能返回多条

                        resultType:指定就是单条记录所映射的java对象类型 

                        ${}:表示拼接sql串,将接受到的参数的内容不加任何修饰拼接在sql中。

                        使用${}容易出现sql注入

                        ${value}:表示接收输入参数的内容,如果传入类型是简单类型,${}中只能使用value-->

                    <select id="findUserByLikeName" parameterType="java.lang.String" resultType="com.changemax.mybatis.po.User">

                        SELECT * FROM user WHERE username LIKE  '%${value}%'

                    </select>

3.7.2程序代码

                // 根据用户名称模糊查询用户

                @Test

                public void findUserByLikeNameTest() throws IOException {

SqlSession session = null;

                    try {

// mybatis配置文件

                        String resource = "SqlMapConfig.xml";

// 得到配置文件流

                        InputStream inputStream = Resources.getResourceAsStream(resource);

// 创建会话工厂,要想build中传入mybatis配置信息

                        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

// 通过工厂得到SqlSession

                        session = factory.openSession();

// list中的user和映射文件中result中resultType所指定的类型一致

                        List<User> userList = session.selectList("test.findUserByLikeName", "小明");

for (User user : userList) {

                            System.out.println(user);

                        }

} catch (Exception e) {

                        // TODO: handle exception

                    } finally {

                        if (session != null) {

                            // 释放资源

                            session.close();

                        }

                    }

}

3.8添加用户

            3.8.1映射文件

                在User.xml中配置哟添加用户的Statement

                    <!-- 添加用户 

                    parameterType:指定输入参数类型是pojo(包括用户信息)

                    #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值

                    -->

                    <insert id="insertUser" parameterType="com.changemax.mybatis.po.User">

                        INSERT INTO user(id, username, birthday, sex, address) value(#{id}, #{username}, #{birthday}, #{sex}, #{address})

                    </insert>

3.8.2程序代码

                // 插入用户

                @Test

                public void insertUserTest() throws IOException {

SqlSession session = null;

                    try {

// mybatis配置文件

                        String resource = "SqlMapConfig.xml";

// 得到配置文件流

                        InputStream inputStream = Resources.getResourceAsStream(resource);

// 创建会话工厂,要想build中传入mybatis配置信息

                        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

// 通过工厂得到SqlSession

                        session = factory.openSession();

// 插入用户对象

                        User user = new User();

                        user.setUsername("麦兜");

                        user.setBirthday(new Date());

                        user.setAddress("江西九江");

                        user.setSex("男");

session.insert("test.insertUser", user);

                        System.out.println(user.getId()+"---------------------------");

session.commit();

} catch (Exception e) {

                        session.rollback();

                    } finally {

                        if (session != null) {

                            // 释放资源

                            session.close();

                        }

                    }

}

3.8.3自增主键返回

                mysql自增主键,执行insert提交之前自动生成一个自增主键。

                通过mysql函数获取到刚刚插入记录1自增主键:

                    LAST_INSERT_ID()

是insert之后调用此函数。

修改insert定义:

<!-- 添加用户 

                    parameterType:指定输入参数类型是pojo(包括用户信息)

                    #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值

                    -->

                    <insert id="insertUser" parameterType="com.changemax.mybatis.po.User">

                        

                        <!-- 将插入数据的主键返回,返回到user对象中

                        SELECT LAST_INSERT_ID():得到刚insert景区记录的主键值,只适用于自增主键

                        

                        keyProperty:将查询到主键值设置到parameterType指定的对象的那个属性

                        order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序

                         -->

                        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">

                            SELECT LAST_INSERT_ID()

                        </selectKey>

                    

                        INSERT INTO user(id, username, birthday, sex, address) value(#{id}, #{username}, #{birthday}, #{sex}, #{address})

                    </insert>

3.8.4非自增抓紧返回(使用uuid())

                使用mysql的uuid()函数生成主键,需要修改表表中id字段类型为string,长度设置为35位。

执行思路:

                    先通过uuid()查询到主键,将主键输入到sql语句中。

执行uuid()语句顺序相对于insert语句之前执行。

                        <!-- 适用mysql的uuid()生成主键 

                        执行的过程:

                            首先通过uuid()得到主键,将主键设置到user对象的id属性中

                            其次在insert执行时,从user对象中取出id属性值

                        -->

                        <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">

                            SELECT UUID()

                        </selectKey>

                        INSERT INTO user(id, username, birthday, sex, address) value(#{id}, #{username}, #{birthday}, #{sex}, #{address})

            

                通过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>

3.9.2代码:

                // 删除用户

                @Test

                public void deleteUserTest() throws IOException {

SqlSession session = null;

                    try {

// mybatis配置文件

                        String resource = "SqlMapConfig.xml";

// 得到配置文件流

                        InputStream inputStream = Resources.getResourceAsStream(resource);

// 创建会话工厂,要想build中传入mybatis配置信息

                        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

// 通过工厂得到SqlSession

                        session = factory.openSession();

session.delete("test.deleteUser", 27);

session.commit();

} catch (Exception e) {

                        session.rollback();

                    } finally {

                        if (session != null) {

                            // 释放资源

                            session.close();

                        }

                    }

}

3.10更新用户

            3.10.1映射文件

                <update id="updateUser" parameterType="com.changemax.mybatis.po.User">

                    UPDATE user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}

                </update>

3.10.2代码

                // 更新用户

                @Test

                public void updateUserTest() throws IOException {

SqlSession session = null;

                    try {

// mybatis配置文件

                        String resource = "SqlMapConfig.xml";

// 得到配置文件流

                        InputStream inputStream = Resources.getResourceAsStream(resource);

// 创建会话工厂,要想build中传入mybatis配置信息

                        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

// 通过工厂得到SqlSession

                        session = factory.openSession();

User user = session.selectOne("test.findUserById", 29);

user.setUsername("王际");

session.update("test.updateUser", user);

session.commit();

} catch (Exception e) {

                        e.printStackTrace();

                        session.rollback();

                    } finally {

                        if (session != null) {

                            // 释放资源

                            session.close();

                        }

                    }

}

3.11总结:

            3.11.1parameterType

                在映射文件中通过parameterType指定输入参数的类型。

3.11.2resultType

                在映射文件中通过resultType指定输出结果的类型。

3.11.3#{}和${}

                #{}表示一个占位符合,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。

                如果接收简单类型,#{}中可以写成value或其他名称。

                #{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

${}表示一个拼接符号,会引用sql注入,所以不建议使用${}。

                ${}接收输入参数,类型可以是简单类型,pojo、hashmap。

                如果接收简单类型,${}只能写成value。

                ${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

3.11.4selectOne和selectList

                selectOne表示查询出一条记录进行映射。如果使用selectOne可以实现使用selectList也可以实现(list中只用一个对象)。

selectList表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne。

如果使用selectOne会报错:

                    org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

3.12mybatis和hibernate本质区别和应用场景

            hibernate:是一个标准的ORM框架(对象关系映射)。入门门槛较高,不需要程序写sql,sql语句自动生成的。

            对sql语句进行优化、修改比较困难的。

                应用场景:

                    适用与需求变化不多的中小型项目,比如:后台管理系统,erp,orm,oa..

mybatis:专注于sql本省,需要程序员自己编写sql语句,sql修改,优化比较方便。mybatis是一个不完全的ORM框架,虽然程序员自动写slq,mybatis也可以实现映射(输入映射、输出映射)。

                应用场景:

                    适用于需求变换较多的项目,比如:互联网项目。

企业进行技术选型,以低成本    高回报作为技术选型的原则,跟据项目组的技术力量进行选择。

4.mybatis开发dao的方法

        4.1SqlSession使用方法

            4.1.1SqlSessionFactoryBuilder

                通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory,将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder。

                在需要创建SqlSessionFactory时,只需要new一次SqlSessionFactoryBuilder即可。

4.1.2SqlSessionFactory

                通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。

4.1.3SqlSession

                SqlSession是一个面向用户(程序员)的接口

                SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(范湖单个或多个对象)。

SqlSession是线程不安全的,在SqlSession实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。

SqlSession最佳应用场合在方法体内,定义成局部变量使用

4.2原始dao开发方法(程序员需要写dao接口和dao实现类)

            4.2.1思路

                程序员需要写dao接口和dao实现类。

                需要向doa实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession

4.2.2dao接口

                public interface UserDao {

                    // 根据id查询用户信息

                    public User findUserById(int id) throws Exception;

// 根据用户名查询用户信息

                    public User findUserByName(String username) throws Exception;

// 添加用户信息

                    public void insertUser(User user) throws Exception;

// 删除用户信息

                    public void deleteUser(int id) throws Exception;

                }

4.2.3dao接口实现类

                public class UserDaoImpl implements UserDao {

                    private SqlSessionFactory sqlSessionFactory;

// 需要向dao实现类中注入SqlSessionFactory

                    public UserDaoImpl(SqlSessionFactory factory) {

                        this.sqlSessionFactory = factory;

                    }

@Override

                    public User findUserById(int id) throws Exception {

                        SqlSession sqlSession = null;

                        try {

                            sqlSession = sqlSessionFactory.openSession();

                            List<User> userList = sqlSession.selectList("test.findUserById", id);

                            if (userList.isEmpty() && userList.size() > 0) {

                                return userList.get(0);

                            }

                            sqlSession.commit();

                        } catch (Exception e) {

                            e.printStackTrace();

                            sqlSession.rollback();

                        } finally {

                            if (sqlSession != null) {

                                sqlSession.close();

                            }

                        }

                        return null;

                    }

@Override

                    public User findUserByName(String username) throws Exception {

                        SqlSession sqlSession = null;

                        try {

                            sqlSession = sqlSessionFactory.openSession();

                            List<User> userList = sqlSession.selectList("test.findUserByName", username);

                            if (userList.isEmpty() && userList.size() > 0) {

                                return userList.get(0);

                            }

                            sqlSession.commit();

                        } catch (Exception e) {

                            e.printStackTrace();

                            sqlSession.rollback();

                        } finally {

                            if (sqlSession != null) {

                                sqlSession.close();

                            }

                        }

                        return null;

                    }

@Override

                    public void insertUser(User user) throws Exception {

                        SqlSession sqlSession = null;

                        try {

                            sqlSession = sqlSessionFactory.openSession();

                            sqlSession.insert("test.insertUser", user);

                            sqlSession.commit();

                        } catch (Exception e) {

                            e.printStackTrace();

                            sqlSession.rollback();

                        } finally {

                            if (sqlSession != null) {

                                sqlSession.close();

                            }

                        }

                    }

@Override

                    public void deleteUser(int id) throws Exception {

                        SqlSession sqlSession = null;

                        try {

                            sqlSession = sqlSessionFactory.openSession();

                            sqlSession.delete("test.deleteUser", id);

                            sqlSession.commit();

                        } catch (Exception e) {

                            e.printStackTrace();

                            sqlSession.rollback();

                        } finally {

                            if (sqlSession != null) {

                                sqlSession.close();

                            }

                        }

                    }

}

4.2.4测试代码

                public class UserDaoImplTest {

                    // 创建SqlSessionFactory

                    private SqlSessionFactory sqlSessionFactory;

/**

                     *

                     * <p>

                     * Title: setUp

                     * </p>

                     * <p>

                     * Description:此方法是在执行下列方法之前执行

                     * </p>

                     * 

                     * @throws Exception

                     */

                    @Before

                    public void setUp() throws Exception {

                        // mybatis配置文件

                        String resource = "SqlMapConfig.xml";

// 得到配置文件流

                        InputStream inputStream = Resources.getResourceAsStream(resource);

// 创建会话工厂,要想build中传入mybatis配置信息

                        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

                    }

@Test

                    public void testFindUserById() throws Exception {

                        UserDao userDao = new UserDaoImpl(sqlSessionFactory);

                        User user = userDao.findUserById(1);

                        System.out.println(user);

                    }

@Test

                    public void testInsertUser() throws Exception {

                        UserDao userDao = new UserDaoImpl(sqlSessionFactory);

                        User user = new User();

                        user.setUsername("asdfasdf");

                        userDao.insertUser(user);

                    }

@Test

                    public void testDeleteUser() throws Exception {

                        UserDao userDao = new UserDaoImpl(sqlSessionFactory);

                        userDao.deleteUser(2);

                    }

}

4.2.5总结原始dao开发问题

                1.dao接口实现类方法中存有大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。

2.调用sqlSession方法时将statement的id硬编码了

3.调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不会报错,不利于程序员开发。

4.3mapper代理方法(程序员只需要mapper接口(相当于dao接口))

            4.3.1思路(mapper代理开发规范)

                程序员还需要编写mapper.xml映射文件

                程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。

开发规范:

                    1.在mapper.xml中namespace等于mapper接口地址

                        <!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 注意:使用mapper代理方法开发,namespace有特殊重要的作用 -->

                        <mapper namespace="com.changemax.mybatis.mapper.UserMapper">

2.mapper.java接口中的方法名和mapper.xml中statement的id一致

3.mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。

4.mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。

                        <select id="findUserById" parameterType="int" resultType="user">

// 根据用户查询用户信息

                        public User findUserById(int id) throws Exception;

总结:以上开发规范主要是对下面的代码进行统一生产:

                        User user = sqlSession.selectOne("test.findUserById", id);

                        sqlSession.insert("test.insertUser", user);

4.3.2mapper.java

                public interface UserMapper {

                    // 根据用户查询用户信息

                    public User findUserById(int id) throws Exception;

                }

4.3.3mapper.xml

                <mapper namespace="com.changemax.mybatis.mapper.UserMapper">

                    <select id="findUserById" parameterType="int" resultType="user">

                        SELECT * FROM USER WHERE id=#{value}

                    </select>

                </mapper>

4.3.4在SqlMapConfig.xml中加载mapper.xml

                <mappers>

                    <mapper resource="mapper/UserMapper.xml" />

                </mappers>

4.3.5测试

                @Test

                public void testFindUserById() throws Exception {

                    SqlSession sqlSession = sqlSessionFactory.openSession();

// 创建UserMapper对象

                    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

User user = userMapper.findUserById(1);

System.out.println(user);

                }

4.3.6一些问题总结

                4.3.6.1代理对象内部调用selectOne或selectList

                    如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。

如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。

4.3.6.2mapper接口方法参数只能有一个是否影响系统开发

                    mapper接口方法参数只能有一个,系统是否不利于扩展维护。

系统框架中,dao层的代码是被业务层公用的。

                    即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。

注意:持久层方法的参数可以包装类型、map...,service方法中不建议使用包装类型(不利于业务层的可扩展)。

5.SqlMapConfig.xml

        mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:

            properties(属性)

            settings(全局配置参数)

            typeAliases(类型别名)

            typeHandlers(类型处理器)

            objectFactory(对象工厂)

            plugins(插件)

            environments(环境集合属性对象)

                environment(环境子属性对象)

                    transactionManager(事务管理)

                    dataSource(数据源)

            mappers(映射器)

5.1properties属性

            需求:

                将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties中就不需要对数据连接参数硬编码。

将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其他xml可以引用该db.properties

                    jdbc.driver=com.mysql.jdbc.Driver

                    jdbc.url=jdbc:mysql://localhost:3306/sql_mybatis?characterEncoding=utf-8

                    jdbc.username=root

                    jdbc.password=123456

在sqlMapConfig.xml加载属性文件:

                    <!-- 加载属性文件 -->

                    <properties resource="db.properties">

                        <!-- properties中还可配置一些属性名和属性值 -->

                        <!-- <property name="" value=""/> -->

                    </properties>

                    <!-- 和spring整合后 environments配置将废除 -->

                    <environments default="development">

                        <environment id="development">

                            <!-- 使用jdbc事务管理,事务控制由mybatis -->

                            <transactionManager type="JDBC" />

                            <!-- 数据库连接池,由mybatis管理 -->

                            <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>

properties特性:

                    注意:mybatis将按照下面的顺序来加载属性:

                        *在properties元素体内定义的属性首先被读取。

                        *然后会读取properties元素中resource或url加载的属性,它会覆盖已经读取的同名属性。

                        *最后读取parameterType传递的属性,它会覆盖已读取的同名属性。

建议:

                        不要在properties元素体内添加任何属性,治安警属性定义在properties文件中。

                        在properties文件中定义属性名要有一定的特殊性,如:xxxx.xxxxx.xxxxx

5.2setting全局参数配置

            mybatis框架在运行时可以调整一些运行参数。

            比如,开启二级缓存、开启延迟加载。。

            全局参数将会影响mybatis的运行行为。

mybatis-setting:

                    Setting(设置)    Description(描述)    Valid Values(验证值组)    Default(默认值)

                    cacheEnabled    在全局范围内启用或禁用缓存配置任何映射器在此配置下。    true | false    TRUE

                    lazyLoadingEnabled    在全局范围内启用或禁用延迟加载。禁用时,所有协会将热加载。    true | false    TRUE

                    aggressiveLazyLoading    启用时,有延迟加载属性的对象将被完全加载后调用懒惰的任何属性。否则,每一个属性是按需加载。    true | false    TRUE

                    multipleResultSetsEnabled    允许或不允许从一个单独的语句(需要兼容的驱动程序)要返回多个结果集。    true | false    TRUE

                    useColumnLabel    使用列标签,而不是列名。在这方面,不同的驱动有不同的行为。参考驱动文档或测试两种方法来决定你的驱动程序的行为如何。    true | false    TRUE

                    useGeneratedKeys    允许JDBC支持生成的密钥。兼容的驱动程序是必需的。此设置强制生成的键被使用,如果设置为true,一些驱动会不兼容性,但仍然可以工作。    true | false    FALSE

                    autoMappingBehavior    指定MyBatis的应如何自动映射列到字段/属性。NONE自动映射。 PARTIAL只会自动映射结果没有嵌套结果映射定义里面。 FULL会自动映射的结果映射任何复杂的(包含嵌套或其他)。    NONE, PARTIAL, FULL    PARTIAL

                    defaultExecutorType    配置默认执行人。SIMPLE执行人确实没有什么特别的。 REUSE执行器重用准备好的语句。 BATCH执行器重用语句和批处理更新。    SIMPLE REUSE BATCH    SIMPLE

                    defaultStatementTimeout    设置驱动程序等待一个数据库响应的秒数。    Any positive integer    Not Set (null)

                    safeRowBoundsEnabled    允许使用嵌套的语句RowBounds。    true | false    FALSE

                    mapUnderscoreToCamelCase    从经典的数据库列名A_COLUMN启用自动映射到骆驼标识的经典的Java属性名aColumn。    true | false    FALSE

                    localCacheScope    MyBatis的使用本地缓存,以防止循环引用,并加快反复嵌套查询。默认情况下(SESSION)会话期间执行的所有查询缓存。如果localCacheScope=STATMENT本地会话将被用于语句的执行,只是没有将数据共享之间的两个不同的调用相同的SqlSession。    SESSION | STATEMENT    SESSION

                    dbcTypeForNull    指定为空值时,没有特定的JDBC类型的参数的JDBC类型。有些驱动需要指定列的JDBC类型,但其他像NULL,VARCHAR或OTHER的工作与通用值。    JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER    OTHER

                    lazyLoadTriggerMethods    指定触发延迟加载的对象的方法。    A method name list separated by commas    equals,clone,hashCode,toString

                    defaultScriptingLanguage    指定所使用的语言默认为动态SQL生成。    A type alias or fully qualified class name.    org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver

                    callSettersOnNulls    指定如果setter方法​​或地图的put方法时,将调用检索到的值是null。它是有用的,当你依靠Map.keySet()或null初始化。注意原语(如整型,布尔等)不会被设置为null。    true | false    FALSE

                    logPrefix    指定的前缀字串,MyBatis将会增加记录器的名称。    Any String    Not set

                    logImpl    指定MyBatis的日志实现使用。如果此设置是不存在的记录的实施将自动查找。    SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING    Not set

                    proxyFactory    指定代理工具,MyBatis将会使用创建懒加载能力的对象。    CGLIB | JAVASSIST

5.3typeAliases(别名)重点

            5.3.1需求

                在mapper.xml中,定义很多的stement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。

如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。

5.3.2mybatis默认支持别名:

                别名        映射的类型

                _byte     byte 

                _long     long 

                _short     short 

                _int     int 

                _integer     int 

                _double     double 

                _float     float 

                _boolean     boolean 

                string     String 

                byte     Byte 

                long     Long 

                short     Short 

                int     Integer 

                integer     Integer 

                double     Double 

                float     Float 

                boolean     Boolean 

                date     Date 

                decimal     BigDecimal 

                bigdecimal     BigDecimal

5.3.3自定义别名

                5.3.3.1单个别名定义

                    <!-- 别名的定义 -->

                    <typeAliases>

                        <!-- 针对单个别名定义 type:类型的路径 alias:别名 -->

                        <!-- <typeAlias type="com.changemax.mybatis.po.User" alias="user" /> -->

</typeAliases>

5.3.3.2批量定义别名(常用)

                    <!-- 批量别名定义 指定包名:mybatis自动扫描包中的po类,自动定义别名,别名急速类名(首字母大小写都可以) -->

                    <package name="com.changemax.mybatis.po" />

5.4typeHandlers(类型处理器)

            mybatis中通过typeHandlers完成jdbc类型和java类型的转换。

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

mybatis支持类型处理器:

                类型处理器            Java类型                JDBC类型

                BooleanTypeHandler     Boolean,boolean     任何兼容的布尔值

                ByteTypeHandler     Byte,byte     任何兼容的数字或字节类型

                ShortTypeHandler     Short,short     任何兼容的数字或短整型

                IntegerTypeHandler     Integer,int     任何兼容的数字和整型

                LongTypeHandler     Long,long     任何兼容的数字或长整型

                FloatTypeHandler     Float,float     任何兼容的数字或单精度浮点型

                DoubleTypeHandler     Double,double     任何兼容的数字或双精度浮点型

                BigDecimalTypeHandler     BigDecimal     任何兼容的数字或十进制小数类型

                StringTypeHandler     String     CHAR和VARCHAR类型

                ClobTypeHandler     String     CLOB和LONGVARCHAR类型

                NStringTypeHandler     String     NVARCHAR和NCHAR类型

                NClobTypeHandler     String     NCLOB类型

                ByteArrayTypeHandler     byte[]     任何兼容的字节流类型

                BlobTypeHandler     byte[]     BLOB和LONGVARBINARY类型

                DateTypeHandler     Date(java.util)    TIMESTAMP类型

                DateOnlyTypeHandler     Date(java.util)    DATE类型

                TimeOnlyTypeHandler     Date(java.util)    TIME类型

                SqlTimestampTypeHandler     Timestamp(java.sql)    TIMESTAMP类型

                SqlDateTypeHandler     Date(java.sql)    DATE类型

                SqlTimeTypeHandler     Time(java.sql)    TIME类型

                ObjectTypeHandler     任意    其他或未指定类型

                EnumTypeHandler     Enumeration类型    VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。

5.5mappers(映射配置)

            5.5.1通过resource加载单个映射文件

                <!-- 映射配置:加载映射文件 -->

                <mappers>

 

                    <!-- 通过resource一次加载一次映射文件 -->

                    <!--<mapper resource="mapper/UserMapper.xml" /> -->

                </mappers>

5.5.2通过mapper接口加载单个mapper

                <!-- 映射配置:加载映射文件 -->

                <mappers>

                    <!-- 通过mapper接口加载映射文件 遵循一些规范: 需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中 

                        上面规范的前提是:使用的是mapper代理的方法 -->

                    <!--<mapper class="com.changemax.mybatis.mapper.UserMapper" /> -->

                </mappers>

5.5.3批量加载mapper(推荐使用)

                <!-- 映射配置:加载映射文件 -->

                <mappers>

                    <!-- 批量加载 mapper 指定mapper接口的包名:mybatis自动扫描包下的所有mapper接口进行加载 需要遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在同一个目录总 

                        上面规范的前提就是:使用mapper代理方法 -->

                    <package name="com.changemax.mybatis.mapper" />

</mappers>

6.输入映射:

        通过parameterType指定输入参数的类型,类型可以是简单类型、hashMap、pojo的包装类型

6.1传递pojo的包装对象

            6.1.1需求

                完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其他信息,比如商品、订单的)

6.1.2定义包装类型pojo

                针对上边需求,建议使用自定义的包装类型的pojo。

                在包装类型的pojo中将复杂的查询条件包装进去。

public class UserQueryVo {

                        // 传入多个id

                        private List<Integer> idList;

// 在这里保证所需要的查询条件

// 用户查询条件

                        private UserCustom userCustom;

public List<Integer> getIdList() {

                            return idList;

                        }

public void setIdList(List<Integer> idList) {

                            this.idList = idList;

                        }

public UserCustom getUserCustom() {

                            return userCustom;

                        }

public void setUserCustom(UserCustom userCustom) {

                            this.userCustom = userCustom;

                        }

// 可以包装其他的查询条件,订单、商品

                        // .....

                    }

6.1.3mapper.xml

                在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询)。

                    <!-- 用户信息综合查询 #{userCustom.sex}:取出包装对象中性别的值 ${userCustom.username}:取出包装对象中姓名的值 -->

                    <select id="findUserList"

                        parameterType="com.changemax.mybatis.po.UserQueryVo"

                        resultType="com.changemax.mybatis.po.UserCustom">

                        SELECT id, username, birthday, address FROM user

<!-- where可以自动去掉条件中的第一个and -->

                        <where>

                            <!-- 引用sql片段的id,如果refid指定的id不在本mapper文件中,需要在前面加namespace. -->

                            <include refid="query_user_where"></include>

                            <!-- 这里还可以引用其他sql片段 -->

                        </where>

                    </select>

6.1.4mapper.java

                // 用户信息综合查询

                public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;

6.1.5测试代码

                @Test

                public void testFindUserList() {

                    SqlSession sqlSession = sqlSessionFactory.openSession();

// 创建UserMapper对象

                    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

UserQueryVo userQueryVo = new UserQueryVo();

                    UserCustom userCustom = new UserCustom();

                    userCustom.setSex("1");

            //        userCustom.setUsername("张三丰");

                    userQueryVo.setUserCustom(userCustom);

                    

                    List<Integer> idList = new ArrayList<Integer>();

                    idList.add(1);

                    idList.add(2);

                    idList.add(5);

                    userQueryVo.setIdList(idList);

List<UserCustom> userCustomList = null;

                    try {

                        userCustomList = userMapper.findUserList(userQueryVo);

                        for (UserCustom userCustom2 : userCustomList) {

                            System.out.println(userCustom2.toString());

                        }

} catch (Exception e) {

                        // TODO Auto-generated catch block

                        e.printStackTrace();

                    }

}

7.输出映射

            7.1resultType

                使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。

                如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。

                只要查询出的列名和pojo中的属性有一个一致,就会创建pojo对象。

7.1.1输出简单类型

                    7.1.1.1需求:

                        用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页。

7.1.1.2mapper.xml

                        <!-- 用户新综合查询总数 parameterType:指定输出类型和findUserList一样 resultType:输出结果类型 -->

                        <select id="findUserCount"

                            parameterType="com.changemax.mybatis.po.UserQueryVo" resultType="int">

                            SELECT COUNT(*) FROM user

                            <!-- where可以自动去掉条件中的第一个and -->

                            <where>

                                <!-- 引用sql片段的id,如果refid指定的id不在本mapper文件中,需要在前面加namespace. -->

                                <include refid="query_user_where"></include>

                                <!-- 这里还可以引用其他sql片段 -->

                            </where>

                        </select>

                

                    7.1.1.3mapper.java

                        // 用户信息综合查询总数

                        public int findUserCount(UserQueryVo userQueryVo) throws Exception;

7.1.1.4测试代码

                        @Test

                        public void testFindUserCount() throws Exception {

                            SqlSession sqlSession = sqlSessionFactory.openSession();

// 创建UserMapper对象

                            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

UserQueryVo userQueryVo = new UserQueryVo();

                            UserCustom userCustom = new UserCustom();

                            userCustom.setSex("1");

                    //        userCustom.setUsername("张三丰");

                            userQueryVo.setUserCustom(userCustom);

int count = userMapper.findUserCount(userQueryVo);

                            System.out.println(count);

                        }

7.1.1.5小结

                        查询出来的结果集只有一行且一列,可以使用简单类型间输出映射。

7.1.2输出pojo对象和pojo列表

                    不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mappr.xml中resultType指定的类型是一样的。

                    在mapper.java指定的方法返回值类型不一样:

                        1.输出单个pojo对象,方法返回值是单个对象类型

                            // 根据用户查询用户信息

                            public User findUserById(int id) throws Exception;

2.输出pojo对象list,方法返回值是List<Pojo>

                            // 根据用户名查询用户信息

                            public List<User> findUserByName(String username) throws Exception;

生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList(返回集合对象调用)

7.2resultMap

                mybatis中使用resultMap完成高级输出结果映射。

7.2.1resultMap使用方法

                    如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系。

                        1.定义resultMap

                            <!-- 定义resultMap 将SELECT id id_, username username_ FROM user 和User类中的属性作一个映射关系 

                            type:resultMap最终映射的Java对象类型,可以使用别名 id:对resultMap的唯一标识 -->

                            <resultMap type="user" id="userResutlMap">

                                <!-- id表示查询结果集中唯一标识 column:查询出来的列名: property:type值得你给pojo类型中的属性名 最终resultMap对column和property作一个映射关系(对应关系) -->

                                <id column="id_" property="id" />

<!-- result表示对普通名映射定义 column:查询出来的列名 property:type指定的pojo类型中的属性名 最终resultMap对column和property作一个映射关系(对应关系) -->

                                <result column="username_" property="username" />

</resultMap>

2.使用功能resultMap作为statement的输出映射类型

                            <!-- 使用resultMap进行输出映射 resultMap:指定定义的resultMap的id,如果这个resultMap在其他的mapper文件中,前面需要加namespace -->

                            <select id="findUserByIdResultMap" parameterType="int"

                                resultMap="userResutlMap">

                                SELECT id id_, username username_ FROM user WHERE id=#{value}

                            </select>

7.2.2将下边的sql使用User完成映射

                    SELECT id id_, username username_ FROM user WHERE id=#{value}

User类中属性名和上边查询列名不一致

7.3小结:

                使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。

                如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系。

8.动态sql

            8.1什么是动态sql

                mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。

8.2需求:

                用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql。

对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。

8.3mapper.xml

                <!-- 用户新综合查询总数 parameterType:指定输出类型和findUserList一样 resultType:输出结果类型 -->

                <select id="findUserCount"

                    parameterType="com.changemax.mybatis.po.UserQueryVo" resultType="int">

                    SELECT COUNT(*) FROM user

                    <!-- where可以自动去掉条件中的第一个and -->

                    <where>

                         <if test="userCustom != null">

                            <if test="userCustom.sex != null and userCustom.sex != ''">

                                AND user.sex = #{userCustom.sex}

                            </if>

<if

                                test="userCustom.username != null and userCustom.username != ''">

                                AND user.username like '%${userCustom.username}%'

                            </if>

                        </if>

                    </where>

                </select>

8.4测试代码

                @Test

                public void testFindUserCount() throws Exception {

                    SqlSession sqlSession = sqlSessionFactory.openSession();

// 创建UserMapper对象

                    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

UserQueryVo userQueryVo = new UserQueryVo();

                    UserCustom userCustom = new UserCustom();

                    userCustom.setSex("1");

            //        userCustom.setUsername("张三丰");

                    userQueryVo.setUserCustom(userCustom);

int count = userMapper.findUserCount(userQueryVo);

                    System.out.println(count);

                }

8.5sql片段

                8.5.1需求:

                    将上面实现的动态sql判断代码块抽取出来,组成一个sql片段。其他的statement中就可以引用sql片段。

                    方便程序员进行开发。

8.5.2定义sql片段

                    <!-- 定义sql片段: id:唯一标识 经验:是基于单表来定义sql片段,这样的话这个sql片段的可重用性高, 在sql片段中不要包括where -->

                    <sql id="query_user_where">

                        <!-- where可以自动去掉条件中的第一个and -->

                        <if test="userCustom != null">

                            <if test="userCustom.sex != null and userCustom.sex != ''">

                                AND user.sex = #{userCustom.sex}

                            </if>

<if

                                test="userCustom.username != null and userCustom.username != ''">

                                AND user.username like '%${userCustom.username}%'

                            </if>

                        </if>

                    </sql>

8.5.3引用sql片段

                    在mapper.xml中定义的statement中引用sql片段:

                        <!-- 用户新综合查询总数 parameterType:指定输出类型和findUserList一样 resultType:输出结果类型 -->

                        <select id="findUserCount"

                            parameterType="com.changemax.mybatis.po.UserQueryVo" resultType="int">

                            SELECT COUNT(*) FROM user

                            <!-- where可以自动去掉条件中的第一个and -->

                            <where>

                                <!-- 引用sql片段的id,如果refid指定的id不在本mapper文件中,需要在前面加namespace. -->

                                <include refid="query_user_where"></include>

                                <!-- 这里还可以引用其他sql片段 -->

                            </where>

                        </select>

8.6foreach

                向sql传递数组或list,mybatis使用foreach解析

8.6.1需求:

                    在用户查询列表和查询总数的statement中增加多个id输入查询。

                    sql语句如下:

                        两种方法:

                            SELECT * FROM USER WHERE id=1 OR id=10 OR id=16

SELECT * FROM USER WHERE id IN(1,10,16)

8.6.2在输入参数类型中添加List<Integer> idList中传入多个id值

                    public class UserQueryVo {

                        // 传入多个id

                        private List<Integer> idList;

8.6.3修改mapper.xml

                    WHERE id = 1 OR id = 10 OR id = 16

                    在查询条件中,查询条件定义成一个sql片段,需要修改sql片段。

<!-- where可以自动去掉条件中的第一个and -->

                    <if test="idList != null">

                        <!-- 使用foreach来遍历传入id 

                            collection:输入    对象中集合属性

                            item:每个遍历生成对象中

                            open:开始遍历时拼接的串

                            close:结束遍历时凭借的串

                            separator:遍历的两个对象中需要拼接的串

                        -->

                        <foreach collection="idList" item="user_id" open="AND (" close=")" separator="OR">

                            id = #{user_id}

                        </foreach>

                    </if>

8.6.4测试代码

                    @Test

                    public void testFindUserList() {

                        SqlSession sqlSession = sqlSessionFactory.openSession();

// 创建UserMapper对象

                        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

UserQueryVo userQueryVo = new UserQueryVo();

                        UserCustom userCustom = new UserCustom();

                        userCustom.setSex("1");

                //        userCustom.setUsername("张三丰");

                        userQueryVo.setUserCustom(userCustom);

                        

                        List<Integer> idList = new ArrayList<Integer>();

                        idList.add(1);

                        idList.add(2);

                        idList.add(5);

                        userQueryVo.setIdList(idList);

List<UserCustom> userCustomList = null;

                        try {

                            userCustomList = userMapper.findUserList(userQueryVo);

                            for (UserCustom userCustom2 : userCustomList) {

                                System.out.println(userCustom2.toString());

                            }

} catch (Exception e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                        }

}

8.6.5另外一个sql的实现

                    <!-- where可以自动去掉条件中的第一个and -->

                    <if test="idList != null">

                    

                        

                        <!-- 实现“ AND id IN(1,10,16)” 拼接-->

                        <!-- <foreach collection="idList" item="user_id" open="AND id IN(" close=")" separator=",">

                            id = #{user_id}

                        </foreach> -->

                    </if>

上一篇:爬取字段 spider_text


下一篇:python3中用django下载文件,中文名乱码怎么办?