程序员Java编程

mybatis入门之增删改查

2018-12-04  本文已影响8人  Eugene1024

一、原生态JDBC程序中问题的总结

1.1 JDBC程序

需求:使用jdbc查询mysql数据库中用户的记录
Statement:向数据库发送回个sql语句
预编译Statement: 好处:提高数据库性能
预编译Statement向数据库发送一个sql语句,数据库执行后将执行结果存放在缓存中,下次再执行相同的语句会直接从缓存中读取
1、 加载数据库驱动
2、 创建并获取数据库链接
3、 创建jdbc statement对象
4、 设置sql语句
5、 设置sql语句中的参数(使用preparedStatement)
6、 通过statement执行sql并获取结果
7、 对sql执行结果进行解析处理
8、 释放资源(resultSet、preparedstatement、connection)

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/test?characterEncoding=utf-8",
                            "root", "root");
            // 定义sql语句 ?表示占位符
            String sql = "select * from t_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) {
                    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问题总结:

上面代码的问题总结

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

2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。

3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
设想:将sql语句及占位符号和参数全部配置在xml中。

4、从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,,不利于系统维护。
设想:将查询的结果集,自动映射成java对象。

二、mybatis原理

2.1 mybatis是什么?

mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis托管到goolecode下,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)。

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

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

2.2 mybatis框架

aaa.png

1、 mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

三、入门程序之mybatis增删改查

3.1 需求

根据用户id(主键)查询用户信息
根据用户名称模糊查询用户信息
添加用户
删除 用户
更新用户

3.2 PC环境

java环境:1.7.0_40
eclipse
mysql: 5.7

3.3 创建mysql数据库

新建数据库mybatis,新建表user


user详细信息

3.4所需Jar包

MyBatis下载地址:https://github.com/mybatis/mybatis-3/releases

mybatis-3.4.4.jar :核心包

mysql-connector-java-5.1.jar:mysql的驱动包

3.4 工程结构

在eclipse中新建java工程,创建下面的工程结构,并把jar把添加到lib中


ccc.png

3.5 配置log4j.properties

开发环境 下日志级别设置为DEBUG, log4j.rootLogger=DEBUG, stdout; 生产环境设置为info或error

# 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.6 配置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">
<configuration>

    <!-- 加载属性文件 -->
    <properties resource="db.properties">
        <!--properties中还可以配置一些属性名和属性值  -->
        <!-- <property name="jdbc.driver" value=""/> -->
    </properties>
    <!-- 全局配置参数,需要时再设置 -->
    <!-- <settings>
    
    </settings> -->
    
    <!-- 别名定义 -->
    <typeAliases>
        
        <!-- 针对单个别名定义
        type:类型的路径
        alias:别名
         -->
        <!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
        <!-- 批量别名定义 
        指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以)
        -->
        <package name="cn.itcast.mybatis.po"/>
        
    </typeAliases>
    
    <!-- 和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>
    <!-- 加载 映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml"/>    
    </mappers>  
</configuration>

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

3.7.1 创建po类

在cn.eugene.po下创建user类

package cn.eugene.po;

public class User {
    private int id;
    private String userName;
    private String userAge;
    private String userAddress;
    public User() {
        super();
        // TODO Auto-generated constructor stub
    }
    /**
     * @return the id
     */
    public int getId() {
        return id;
    }
    /**
     * @param id the id to set
     */
    public void setId(int id) {
        this.id = id;
    }
    /**
     * @return the userName
     */
    public String getUserName() {
        return userName;
    }
    /**
     * @param userName the userName to set
     */
    public void setUserName(String userName) {
        this.userName = userName;
    }
    /**
     * @return the userAge
     */
    public String getUserAge() {
        return userAge;
    }
    /**
     * @param userAge the userAge to set
     */
    public void setUserAge(String userAge) {
        this.userAge = userAge;
    }
    /**
     * @return the userAddress
     */
    public String getUserAddress() {
        return userAddress;
    }
    /**
     * @param userAddress the userAddress to set
     */
    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", userName=" + userName + ", userAge=" + userAge + ", userAddress=" + userAddress
                + "]";
    }   
    

}

3.7.2 映射文件

在项目目录的sqlmap下创建user的映射文件userMapp.xml,并配置根据id查询用的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">

<mapper namespace="test">
    <!-- 根据id查询用户信息 -->
    <select id="findUserById" parameterType="int" resultType="cn.eugene.po.User">
        select * from user where id = #{id}
    </select>   
 
</mapper>

3.7.3 在SqlMapConfig.xml加载映射文件

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

3.7.4 编写测试程序,根据id查询用户信息

package cn.eugene.first;

import java.io.IOException;
import java.io.InputStream;

import org.junit.Test;

import cn.eugene.po.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;

public class MybatisFirst {
    
    @Test
    public void findUserByIdTest() throws IOException{
        //得到配置文件流
        String resource = "SqlMapConfig.xml";
        InputStream inputstream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
        //通过会话工厂得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("test.findUserById", "1");
        System.out.println(user);
        sqlSession.close();     
    }
    
    

    @Test
    public void deleteUser() throws IOException {
        String resource = "SqlMapConfig.xml";
        InputStream inputstream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
        //通过会话工厂得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();    
        sqlSession.delete("test.deleteUser", "2");
        sqlSession.commit();
        sqlSession.close();
    }
    
    @Test
    public void updateUser() throws IOException {
        String resource = "SqlMapConfig.xml";
        InputStream inputstream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
        //通过会话工厂得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();    
        User user = new User();
        user.setId(2);
        user.setUserName("出运费");
        user.setUserAge("21");
        user.setUserAddress("重庆");
        sqlSession.update("test.updateUser", user);
        sqlSession.commit();
        sqlSession.close();
    }    
    

}

3.8 添加用户

sql配置

<insert id="insertUser" parameterType="cn.eugene.po.User">
        insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress})
    </insert>

测试方法

    @Test
    public void insertUser() throws IOException {
        String resource = "SqlMapConfig.xml";
        InputStream inputstream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
        //通过会话工厂得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();    
        User user = new User();
        user.setUserName("出运费");
        user.setUserAge("21");
        user.setUserAddress("重庆2");
        sqlSession.update("test.insertUser", user);
        sqlSession.commit();
        sqlSession.close();
    }

3.9 删除用户更新用户

sql配置

<!-- 根据id删除用户 -->
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>
    
    <update id="updateUser" parameterType="cn.eugene.po.User">
        update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id= #{id}
    </update>

测试方法

    @Test
    public void insertUser() throws IOException {
        String resource = "SqlMapConfig.xml";
        InputStream inputstream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
        //通过会话工厂得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();    
        User user = new User();
        user.setUserName("出运费");
        user.setUserAge("21");
        user.setUserAddress("重庆2");
        sqlSession.update("test.insertUser", user);
        sqlSession.commit();
        sqlSession.close();
    }

3.10添加用户主键返回

    <insert id="insertUser2" parameterType="com.ganlion.po.User">
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress})
    </insert>

测试方法

@Test
    public void insertUser2(){
        InputStream inputstream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis的配置文件信息
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
        //通过会话工厂得到SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();    
        User user = new User();
        user.setUserName("飛天");
        user.setUserAge("24");
        user.setUserAddress("上海浦江");
        session.insert("test.insertUser2", user);
        session.commit();
        System.out.println("返回的插入的主鍵id:"+user.getId());
        session.close();
    }

四、总结

sql配置文件中

parameterType指定输入参数类型
resultType指定输出参数类型
#{}表示一个占位符,#{}接收输入参数。#{}可以有效防止sql注入。类型可以是简单类型,pojo、hashmap。如果接收简单类型,#{}中可以写成value或其它名称。

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

${}表示一个拼接符号,拼接sql串,会引起sql 注入存在安全隐患,所以不建议使用${}。${}接收输入参数,类型可以是简单类型,pojo、hashmap。如果接收简单类型,${}中只能写成value。

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

五、编写入门程序可能遇到的问题

问题一、Could not find resource SqlMapConfig.xml

ddd.png

原因:一开始是因为默认的情况下,只有src是build path的source folder目录,自定义的文件夹在Use as Source Folder前只是一个普通的文件夹,默认的情况下不会被加载,需要手动将自定义的文件夹加载为source folder。也就是之前所说的步骤。

解决办法:右键点击SqlMapConfig.xml所在的文件夹(我的是config)------>Build Path------>Use as Source Folder

参考mybatis中遇到Could not find resource SqlMapConfig.xml

问题二、当查询数据库数据的时候,控制台System.out.println(user)输出了NULL

注意sql配置文件查询的字段和数据库对应

上一篇下一篇

猜你喜欢

热点阅读