Mybatis

1.Mybatis:        (是一款优秀的持久层框架,它支持 SQL、存储过程以及高级映射)

        注解:        使用注解,不需要有XML配置文件,需要将代码和SQL写在一起

        XML:        把SQL语句放到XML文件中

2.Mybatis环境搭建:

        导包:                 

        创建jdbc.properties 和 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>
	<!-- 设置别名 -->
    <!-- <typeAlias type="类的全路径" alias="别名"/> -->
	<!-- 
        typeAliases>
		    <typeAlias type="cn.java.entity.User" alias="User"/>
	    </typeAliases>
    -->
	
	<!-- 数据库配置文件,会自动解析 -->
	<properties resource="jdbc.properties"></properties>
	<!-- 设置环境 -->
	<environments default="mysql">

		<!-- 配置mysql -->
		<environment id="mysql">
			<!-- 配置事务,由JDBC实现 -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 配置数据源 -->
			<dataSource type="POOLED">
				<!-- 这里的${}不是EL表达式,而是OGNL表达式 -->
				<property name="driver" value="${driver}"/>
				<property name="url" value="${url}"/>
				<property name="username" value="${username}"/>
				<property name="password" value="${password}"/>
			</dataSource>
		</environment>

        <!-- 使用p6spy打印日志(导入p6spy的jar包和spy.properties文件) -->
		<environment id="p6spy">
			<!-- 配置事务 -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 配置数据源 -->
			<dataSource type="POOLED">
				<!-- 这里的${}不是EL表达式,而是OGNL表达式 -->
				<property name="driver" value="${driver}"/>
				<property name="url" value="${url}"/>
				<property name="username" value="${username}"/>
				<property name="password" value="${password}"/>
			</dataSource>
		</environment>
	</environments>
	<!-- 关联局部配置文件(映射) -->
	<mappers>
		<mapper resource="cn/java/entity/User.xml"/>
		
		<!-- 注解方式用class,并且写类全名 -->		
		<!-- <mapper class="cn.java.dao.UserDao"/> -->
	</mappers>
</configuration>

        导入log4j.properties:

        书写 Mybatis的局部配置文件(存放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:命名空间,其值为某一dao层类的具体路径,用于调用的映射
	调用方式:namespace.id
 -->
<mapper namespace="cn.java.entity.User">
	<!-- 
		sql语句必须保存在Mybatis的局部配置文件中
	 -->
	<!-- 
		select标签存放查询语句
			id:整个配置文件中id值必须唯一,表示调用sql的名字,相当于方法名
			
			resultType:指定当前sql语句返回的数据类型(存放其中一条数据的类型,而不是sql语句最终类型)
			
		1 SQL语句中尽量不要出现 < > ,用&lt; 和&gt; 代替
		
		2 
		返回值类型:
			resultType:能够自动注入,前提是 数据库查询的列必须和成员变量一致,如果不一致,可以使用别名的方式或者手动映射
			resultMap:数据需要手动注入,一般为查询列和成员变量不一致时使用,尤其是多表查询
		参数类型:
		parameterType:入参类型,写类全名,如果有别名可以使用别名代替
		parameterMap:和resultMap想类似,基本上不用
	 -->
	<select id="getAllUsers" resultType="cn.java.entity.User">
		select * from users
	</select>
    
    <insert id="add" parameterType="cn.java.entity.User">
        <!-- 这里的 #{username} 就等于是用PreparedStatement的 ? 方式,传递的参数会自动映射到username的属性上 -->
		insert into users(username,password) values(#{username},#{password})
	</insert>

    <delete id="delete" parameterType="java.lang.Integer">
		<!-- 如果有多个入参,也可以用#{arg0}代替#{id} -->
		<!-- 如果是单个个入参,也可以用#{0}代替#{id} -->
		delete from users where id=#{arg0}
	</delete>
</mapper>
public interface UserDao {
    /*
     * 参数可以同过#{arg0},#{arg1}...的传入
     */
    @Insert("insert into users(username,password) values(#{username},#{password})")
    int add(String username, String password);

    @Insert("insert into users(username,password) values(#{username},#{password})")
    int addUser1(User user);

    /*
     * 无论是实体类,还是map集合传参,均可以通过key/属性名来获取值
     */
    @Insert("insert into users(username,password) values(#{username},#{password})")
    int addUser2(Map<String, String> userMap);
}

        测试:        :        增、删、改必须通过commit提交事务才生效

public class TestUser {
    // @Before:在Test之前执行
    // @After:在Test之后执行

    // 查询操作
    @Test
    public void getAllUsers() throws IOException {
        // SqlSession---->SqlSessionFactory---->SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
        // 将mybatis.xml文件转化成流
        InputStream ips = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory ssf = sfb.build(ips);
        SqlSession session = ssf.openSession();

        // 2、调用局部配置文件中的sql语句
        // selectList:查询多条记录    selectOne:查询单条记录
        List<User> selectList = session.selectList("cn.java.entity.User.getAllUsers");
        for (User user : selectList) {
            System.out.println(user);
        }
    }

    @Test
    public void add() throws IOException {
        // SqlSession---->SqlSessionFactory---->SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
        // 将mybatis.xml文件转化成流
        InputStream ips = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory ssf = sfb.build(ips);
        SqlSession session = ssf.openSession();

        User user = new User("admin", "root");
        Map<String, String> userMap = new HashMap<String, String>();
        userMap.put("username", "admin");
        userMap.put("password", "root");
        // 局部配置文件xml方式
        // int num = session.insert("cn.java.entity.User.add", user);

        // 注解方式
        // int num = session.insert("cn.java.dao.UserDao.addUser1",user);
        // int num = session.insert("cn.java.dao.UserDao.addUser2", userMap);
        session.getMapper(UserDao.class).addUser1(user);// 接口代理方式也是getMapper,接口代理需要局部配置文件和对应的接口,接口中不需要添加注解,主配置文件中映射局部配置文件

        // 提交事务
        session.commit();
        // 关闭资源
        session.close();
    }

    @Test
    public void delete() throws IOException {
        // SqlSession---->SqlSessionFactory---->SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
        // 将mybatis.xml文件转化成流
        InputStream ips = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory ssf = sfb.build(ips);
        SqlSession session = ssf.openSession();

        int num = session.delete("cn.java.entity.User.delete", 147);
        session.commit();
        session.close();
    }
}

3.# 和 $ 的区别:

        #获取参数值时,会解析成?,默认会把参数当做字符串处理,在参数之间会添加单引号

        $ 不会解析成?,不会加单引号

4.动态SQL:        if、choose(when、otherwise)、where等标签

public class StudentDaoImpl implements StudentDao {

    @Override
    public List<Student> list(Map<String, Object> map) 
        SqlSession session = MyBatisUtil.getSession();// MyBatisUtil 将获取SqlSession封装成一个工具类
        List<Student> students = session.selectList("cn.java.dao.impl.StudentDaoImpl.list", map);
        return students;
    }
}
<?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="cn.java.dao.impl.StudentDaoImpl">

	<!-- 需要传递多个参数的时候  就需要设置为map -->
	<select id="list" parameterType="map" resultType="cn.java.entity.Student">
		select * from students 
		<where>
            <!-- 如果if中的test判断为false,则sql语句中不会有where -->
			<if test="stuName!=null">
				stuName like #{stuName}
			</if>
		</where>
		<!-- 
			# 会自动添加''
			$ 不会添加''
		 -->
		<if test="sort!=null">
			order by ${sort}
			<choose>
				<when test="order!=null">
					${order}
				</when>
				<!-- 默认 -->
				<otherwise>asc</otherwise>
			</choose>
		</if>
	</select>
</mapper>

5.resultMap:        

        resultType:        将查询结果集中的各个列--映射到java对象中与列名一致的属性中(只有列名与属性名相同,才能映射成功)

        resultMap:        将查询结果集中的列--映射到java对象的各个属性上,这种映射是根据用户在resultMap的子标签中的配置来决定的

        多对一查询:

public class Address {
    private int id;
    private String addr;
    private String phone;
    private String postcode;
    private User user;// 将User对象封装到Address对象中,即多条address对应一个user

    // (...省略构造方法,get/set方法)
}

                AddressDaoImpl.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">
<mapper namespace="cn.java.dao.impl.AddressDaoImpl">

    <select id="load"  parameterType="int"   resultMap="addressMap" >
			select * from t_address where id = #{id}
            <!-- 表中列为:id,addr,phone,postcode,user_id -->
	</select>

    <!-- 在resultMap中设置关联关系 -->
    <!-- 
        type:是指对象所在的类
        autoMapping:是否自动映射,如果为false,需要手动设置(result标签)每个属性
     -->
    <resultMap type="cn.java.entity.Address" id="addressMap" autoMapping="true">
        <!--
            property: 代表的是实体类中的属性名
            javaType: 代表的是实体类中属性名的类型
            column: 数据库中查询语句的字段名(与实体类属性向对应的,可以与实体类属性名不同)
            jdbcType: 数据库中查询字段名的类型

            <result property="" javaType="" column="">
        -->
	<!--    
        association : 联系,关联
			property : Address中哪个变量保存关联对象(user)的引用
			column : 数据库中的关联列,在数据库中以哪列来保存关联表的引用
			javaType : 关联类的类型是什么(需要全名,使用设置的别名也可以)
            select: 查询关联对象调用的方法,不用单独去写,可以直接调用User.xml中的查询方法即可
	 -->
			<association property="user"  column="user_id" javaType="cn.java.entity.User"  select="cn.java.dao.impl.User.load"" />
        <!-- 
            User.load:    select * from t_user where id=#{id}
         -->
	</resultMap>
</mapper>

                        第二种写法:        通过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="cn.java.dao.impl.AddressDaoImpl">
    <select id="load" parameterType="int" resultMap="addrMap">
		select * from t_address ta inner join t_user tu on ta.user_id=tu.id where ta.id=#{id}
	</select>

    <resultMap type="cn.java.entity.Address" id="addrMap" autoMapping="true">
		<!-- 
			id:其中为了多表查询得到多个结果时,确保数据的唯一性
				如果不加id映射,则查询多条数据时,就会只有一条数据
                如果当前查询只有一条结果数据,加不加都可以
		 -->
		<id property="id" column="id"/>
		<association property="user" column="user_id" javaType="cn.java.entity.User" resultMap="userMap"></association>
	</resultMap>
	
	<resultMap type="cn.java.entity.User" id="userMap" autoMapping="true">
        <!-- 
            因为结果集中的id是address的id,而不是user的id 
            当结果集中的列名与实体类中的变量不一致,需要手动映射,否则user的id就变成address的id值
        -->
		<result property="id" column="user_id"/>
	</resultMap>
</mapper>

        一对多查询:

public class User {
    private int id;
    private String username;
    private String password;
    private String nickname;
    private int type;
    private List<Address> addresses;// 把address封装到集合中
    
    // (...省略get/set方法,构造方法)
}

                UserDaoImpl.xml:        : 向集合中映射时,collection中必须用ofType来设置集合中的元素类型

<?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="cn.java.dao.impl.UserDaoImpl">
	
	<select id="load" parameterType="int" resultMap="userMap">
		select *,ta.id as address_id from t_user tu inner join t_address ta on tu.id=ta.user_id where tu.id=#{id}
	</select>
	
	<resultMap type="cn.java.entity.User" id="userMap" autoMapping="true">

		<id property="id" column="id"/>
		<!-- 手动映射 -->
        <!-- <result property="username" javaType="String" column="username"/> -->

		<!-- 
			collection:集合
				property:User类中哪个变量存放这address的引用
				ofType:集合中的元素类型
				column:哪个列对应(用这个字段名来表示映射关系)(大多数是用于连接两个表的字段名)
		 -->
		<collection property="addresses" ofType="cn.java.entity.Address" column="user_id" autoMapping="true">
            <!-- 如果这里不用id,而用result进行映射,则不能区分唯一性,导致集合中只有一条元素 -->
            <!-- 如果上面加了id映射,那么这里可以把id标签改写成result标签 -->
			<id property="id" column="address_id"/>
            <!-- <result property="addr" column="addr" jdbcType="VARCHAR"/> -->
		</collection>
	</resultMap>
</mapper>

6.调用存储过程:

    @Test
    public void proTest(){
        Map<String,Object> paramMap = new HashMap<String,Object>();
        paramMap.put("num1",10);
        paramMap.put("num2",20);
        session.selectOne("cn.java.dao.impl.GoodDaoImpl.proTest",paramMap);
        System.out.println(paramMap);
    }

        GoodDaoImpl.xml:

	<!--调用存储过程-->
	<select id="proTest" parameterType="Map" statementType="CALLABLE">
		call pro_sum(
			#{num1,mode=IN,jdbcType=INTEGER},
			#{num2,mode=IN,jdbcType=INTEGER},
			#{sum,mode=OUT,jdbcType=INTEGER}
		)
	</select>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值