Spring Data JDBC Tutorial: How to simplify data access in Spring Boot

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello there my name is Dan Vega and I'm a spring developer advocate for VMware today I want to go in and build a new spring boot application that connects to a database and we're going to use a project called springdata jdbc now you may have heard a pro heard of a project called Spring data jpa which is by far the most popular project underneath the spring data umbrella but that is using an orm or an object relational mapper and specifically using hibernate and hibernate is great but if you're brand new to Spring Boot and brand new to Spring data if you've never used an RM before it can be a little overwhelming at first so spring data aims to kind of simplify a lot of the pain of getting started with something like hibernate so we'll talk more about some of the nuances as we go along if you have used jpa before I want you to kind of forget some of that because you may be trying to use spring data jdbc like you would with jpa and that's not the case so what we're going to do let's start building a Blog application and as we go along we'll take a look at the documentation we'll talk about some of the concepts that are coming that are going to come up and uh we'll just we'll have we'll have some fun doing it along the way so I'm over here at start.spring.io our second favorite place on the internet and this is a great place to go ahead and bootstrap a new spring boot application so I'm choosing Maven as my build tool I'm choosing Java as my language I'm choosing 2.7.4 which is the latest stable release of spring Boot and what I'm going to do is come in here and add a group so I'm going to say dev.dan Vega the artifact is going to be blog and all of this information looks pretty good now I need some dependencies I'm going to add spring web I'm also going to add spring data jdbc and then for that we'll also need a database so I'm going to use H2 which is a nice in-memory database really kind of helps simplify this particular project and you know anything anytime you're trying trying to just kick up a tutorial or a demo or proof of concept H2 is a really great choice so with that I will go ahead and hit generate it is going to download a zip I can then go ahead and open that in my favorite IDE which is IntelliJ you can open it up in whatever ID or text editor you're most comfortable with and with that we'll go ahead and start writing some code all right the first thing we got to come in here and do is go ahead and open up Source main Java and we will go ahead and create a new package in here we'll call this model and we're going to start with the idea of a blog post so we're going to create a new class called post I'm going to leave this as a regular post or a regular class not a record as I usually do because they're we're gonna have to do some things in here that we'll get to later and I'd like to keep it this way for now so what we need to do is we need to create a few fields in here so I'm going to say private integer ID private string title we'll also have some string content and what I also want to do is add a local date time oops date time for when it was published so published on and then I'll do the same for what it was updated on so I'll say updated on and then eventually we will tie an author and some comments to this as well but we'll come back to that a little bit later so what I want to do now is create a Constructor so this Constructor is going to take in a title and it's going to take in some content and that's really it so we could say this dot title is equal to title this dot content is equal to content and then what I'm going to do is go ahead and set the published on equal to the local date time dot now and then um we'll just go ahead and leave the updated value so updated on will be null so we'll store that as no on the database and the reason for that is when I publish an article I want that time to be displayed and only when the updated on is not null do I want to go ahead and display that letting the user know letting the viewer know that hey this this article may have been published last year but it was just updated recently so that is a good start we'll go ahead and create some Getters and Setters here we will also go ahead and create a tostring and that looks good now one last thing with spring data jdbc we have to mark one we have to mark the field that is going to be our ID with the at ID annotation so this is coming from org.springframework.data.annotation.id different than jpa if you've used jp8 in the past you know this is coming from something like Java x dot persistence so that's not what that is here so we have our ID the next thing we need to do is go ahead and create a table that will line up with this post so I'm going to go under Source main resources and I'm going to create a new file we're going to call this schema.sql and what we need to do is create let's actually get rid of these first so we're going to change the dialect to this is going to be H2 and I can go ahead and disable this inspection so we're going to have a post table we'll say create table post and I always forget that semicolon so let's add that now so we're going to have an ID which is going to be an INT we'll say this is auto increment we'll have the primary key I'm also going to go ahead and add a version we'll talk about this as we go it's really specific it's kind of specific to Spring data jdbc on how we know it's gonna you know how we know we're we're creating a new one or updating an existing one you can get away with this when you first start but you may need this later um so I'm going to go ahead and also have a title so we'll say this is a far car 255 not null we'll also have the content as text we don't want that and all and then we'll have published on so that's going to be a time stamp we do we do want allow we do want to allow nulls there so I'll go ahead and keep that and then I think that's it for now so we'll come back to this again we're going to be talking about um having you know an author of a post having comments in a post but I think this is a good start okay so the next thing we'll want to do here is come into our application.properties instead of few Fields so we're using uh the H2 database we want to enable that console so that we can go ahead and get some insight as to you know what tables and columns are being created make sure everything looks right we can also run SQL from there I actually have a whole video on just how to connect to and configure the H2 console or the H2 database in your spring boot app so I'll go ahead and try and Link that above and below so the next thing we need to do is we need to there's a generate unique name property on the H2 data source we want to say false for that we don't want to generate a unique name we want to go ahead and set a data source name and we're going to set that data source name to blog okay so with all of those things in place we're getting closer we're getting closer we have this post now we have the idea of repositories in Spring data so we're going to create a repository package and in the repository we're going to create a new interface so this is going to be called post repository this is going to be an interface and all we're going to do here is extend the crud repository which accepts a type and an ID type so this type is going to be of post and then the ID type in our post is an integer so that's all we need to do and just by doing that we get some crud functionality out of the box things like save save all find all find one delete Etc okay so most of our pieces are in place we can now go ahead and start to add some data to the database now we could go into our ddl script there that created the table and the columns and we can insert some data that way we can also do it another way here in our main blog application class I'm going to create a new Bean which is of type command line Runner so command line Runner and inside of this is actually a functional interface so we're going to go ahead and return args and then what I want to do is get an instance of that post repository so post repository posts and inside here I can now create a new post so I'm going to say posts.save and we're going to create a new post so remember the post Constructor takes a title and some content so I'm going to say this is um let's say hello world and then the content is welcome to my blog so that's all we need to create a post so this should go ahead and persist this off to the database just to make sure everything's working let's go ahead and run this app all right um looks like everything's working our H2 console is available and our database is available at gwc H2 memory yeah so that stands for in-memory and then blog so let's head over to the browser and check that out okay so I'm going to go ahead and log in here and you can see we have a post table if you kind of drill down into it you can see all the columns if you go ahead and click on it we can execute this SQL statement and you see that we get our one row that we inserted so we have a title we have a Content published on was the time stamp and then updated on is going to be null for now all right so so far everything that we've done pretty straightforward this is probably a good time to start talking about spring data jdbc specifically so if you head over to spring.io project spring data jdbc underneath the learn tab we can go ahead and look at the reference documentation it's a really great place to start under reference documentation this is really kind of the start of where we want to begin this journey so why spring data jdbc when we have something like spring data jpa as I mentioned early on in this tutorial spring spring data jpa is great but it also comes with a lot of overhead and again for someone new or even someone who's been doing this a long time it can be a little overwhelming there are things that you have to deal with things like tracking changes to entities it does lazy loading for you but that's something you have to like understand how that is happening um it also does some really you know interesting things the way it keeps track of those changes it has things like eager and lazy loading you can you know when you have all of these objects you have this huge graph of things so it's it's often confusing on like well when I save this one thing how does you know what happens with everything else so spring data jdbc as it says here aims too much aims to be much simpler conceptually by embracing the following design decisions so if you load an enemy SQL gets SQL statements get run once it's done you've completely loaded an entity there is no lazy loading or no caching now you can do caching in Spring but spring data jdbc is not doing that for you if you save an entity it gets saved if you don't it doesn't there is no dirty tracking no session Etc um the other thing that you need to think about again this is comes back to if you've done spring data jpa in the past there's a simple model of how you map entities to tables um it works rather you know it probably only works for rather simple simple cases if you don't like that you should um code your own strategy but spring data jdbc offers a limited support for customizing that strategy uh within annotations so when we talk about modeling our entities to tables we have that post entity that we've already created that gets mapped to a post table now we know we need to start thinking about how do we you know what about other models in our application if we have an author if we have a comment how do those things get related if there's no lazy loading eager fetching what happens there and this is the first thing you really need to wrap your head around if you came from something like spring data jpa so I'm not going to go through all this but this documentation is something I would look into as you as you start diving in and get stuck the the first two pair the first two paragraphs here are important um all the spring data modules are inspired by this concept of repository aggregate aggregate route from domain driven design these are all possible these are possibly even more important in Spring data jdbc because they are to some extent contrary to normal practice when working with relational databases so it's important to understand those concepts of aggregate and aggregate root there's a really good definition over on Mountain Fowler's website talking about aggregate is a pattern in domain-driven design the example comes you know there's a couple examples in there but we also mentioned a similar example here in the documentation but an aggregate is really a group of entities that is guaranteed to be consistent between atomic changes to it a classic example of this is order with order items a property on order for example number of items is consistent with the actual number of order items um so understanding what Agri Aggregates are aggregate routes it's an important concept for what we're going to get into now so if you want to take some time to go through the documentation if you haven't read domain driven design by Eric Evans I wouldn't say pause this video and do that because that's going to take a long time but just kind of getting up to date with some of those Concepts so with that let's head back to the application okay so now I want to talk about creating an author so an author doesn't really belong to a post an author kind of stands on its own so this is going to be its own aggregate so when we talk about Aggregates in Spring data jdbc what we're talking about here is will it have its own repository do I need to go look up authors specifically just to find an author and in this case I think yes so we're going to have an author stand on its own it's going to be its own aggregate so we're going to create a new model so I'm going to create a new Java class we're going to call this author this one is going to be pretty simple so I'm going to go ahead and create a record and this record is going to have an integer ID we'll say a string first name string last name string email and string username okay so with all those properties in place I'm going to go ahead and Mark this with that ID and let's see if we can't put these on separate lines that looks good so now that we have that we want to create a repository for that so I'm going to come in here and create an author repository and that's going to be an interface again extends credit repository the type is author the ID type is integer so with that we're getting closer we need to go back down to our schema and now we need to go ahead and update our schema here so we are going to create a new table here for let's say author so I'm going to create a table called author again some of the same stuff here let's just copy that oh boy look at that that's what I get for copy pasting um so we're going to have first name that is going to be of our car of 100 not no we'll have a last name that looks pretty similar we're going to have an email so this is going to be let's just make this a little bit longer we don't want that and all and finally we have a username this is going to be 100 and we don't want that no okay so so far it looks pretty good right now in a normal schema design here we need to have a way to kind of tie these two together right when I'm writing a new post on my blog I am the author I need to somehow let that post know that I am the one writing it and the way that we usually do this is by having a foreign key so here what I want to do is I'm going to say um oops I'm going to say the author is going to have of type integer and what I'll say is foreign key so the foreign key author is going to reference author ID and so that will kind of tie those together so when we insert a new post we are going to insert the ID of the author into the author column all right so now we were able to go ahead and model that relationship between the database tables so we have this ID we are tying an author to a post but how do we represent that in our Java code and that's where we need to go ahead and take a look at the documentation again so if we look at supported types in your entities one of the things down here in the documentation we'll kind of go through that and explain it but basically if you have an N to one or n to M so one to one or one-to-many references you are by definition dealing with two separate Aggregates here's something that was that really stuck out for me when I was trying to learn this basically in Spring data jdbc you're managing two types of relationships relationships between Aggregates so post an author the one that we're looking at now and then relationships within aggregate Roots so as we get to posts and comments I'll remind you of this again but that's a separate type of relationship we're managing so this one we're managing a relationship between two Aggregates between post and author so references between those may just be encoded as a simple ID in my post I have an author ID and that's how I kind of map between them a better way to encode these is to make them instances of aggregate reference and an aggregate reference is really just a wrapper around an ID value which marks that value as a reference to a different aggregate also type also the type of the aggregate is encoded in the type parameter like it is here so knowing that let's go back to our code here and in post we're going to come back and fill in this author and so what we're going to do here is we're going to say private aggregate reference so aggregate reference the type is an author and then we need to pass in the ID type so that is an integer and we'll just call this author so now we've kind of mapped those two so now we can do is go back to our blog application and what we want to do is we want to create a new author so to do that I want to go ahead and get a reference to the author repository we'll call this authors and now in here I can say authors dot save and so I'm going to create a new author so I'm going to create a new author now this is a record in Spring data jdbc we need to pass in some kind of ID here what we want to do is we want to pass in null if you pass in any type of ID spring data jdbc thinks that it's performing an update in this case we pass in null it thinks it's going to do an insert so we're going to pass in null we're going to pass in Dan as the first name Vega danvega gmail.com and then the username will be the Vega so that is going to create a new author in the database but what we want to get back from this is actually that aggregate reference right because when we create a new post we want to pass in that aggregate reference so to do that I'm going to say aggregate reference and then there is a static method on there called 2 so I can say 2 and let's go ahead and add one more here and that will give us back exactly what we need to go ahead and pass the post so I'm going to introduce the local variable we'll go ahead and call this let's just call it Dan and now I can go ahead and update my post so I want to say aggregate reference of author integer we'll call this author and now what I can do is say this dot author is equal to author so we have one problem we need to go ahead and update our Constructor call here and so let's go ahead and pass in Dan okay and we're getting an error here what did we do here so we're calling new author uh we probably need to get back that ID for this to work huh no what did we do wrong here oh aggregate reference of that should be author and integer and then what is this saying uh no instance of type variable exists so the author conforms your integer what did we do we need to get back the ID that should work okay so no more errors we're persisting a new author to the database and what we want to get back is that aggregate reference so then we can pass that into posts now again remember so if you're coming from the spring data jpa world you might have some way of cascading that save down right in Spring data jdbc these are two separate Aggregates so we need to save the author aggregate first we need to save the post next in this case we're just setting the reference to that particular author so let's see if this works I'm going to go ahead and restart that see if we can go ahead and start up without any errors oh so far so good let's head back to the H2 Council and I'll go ahead and connect to this and we see we have post and author let's go ahead and see this so good I do have an author in there let's go ahead and hit post so we have an ID version title content published updated and we have an author ID of one which again is our primary key back to the author table all right so far so good uh now we need to take a look at comments so we have the idea of an author and a post we need to go ahead and model out a comment so let's go ahead and create a comment this is just going to be a class we'll call it comment and in here we'll create a few Fields we'll say private string name private string content again I'm going to do like a private let's say local dates time published on and then what if we go ahead and update that comment let's do something similar so we'll say updated on and I think that's it so then we'll go ahead and create a I'm sorry a public comment again I'll just take in a name and the content so whatever the comment is and then I will say this dot name is equal to name this dot content is equal to content okay let's create some Getters and setters and we'll do that and then we'll also go ahead and create a tostring all right so far so good now the big difference here is this comment is not going to be an aggregate this is going to belong to a post so the aggregate route for this is going to be a post so when we talk about Aggregates do we say like can this comment kind of live and breathe on its own now in a much larger blogging application maybe it does maybe there's a scenario where I need a repository for comments I need to be able to find all the comments I need to like do a whole bunch of filtering and paging and sorting on comments for my tiny blog on the internet that you know I've been blogging for 20 years and I almost never got comments maybe my work is just not not that interesting but you know in my scenario I know what the amount of comments are going to be so I think that this really is something that's going to belong to a post so in aggregate is we have all these different objects that all kind of belong to one entity if you will so Post in a comment kind of Belong Together so how does that work so now we're not we will have a separate table for this but we're not you know you notice that we don't have an ID in here we're not going to mark this with that ID we're not going to have a repository for it so let's go back let's start with the schema so we need to create a schema for comment what does that look like so we'll come in here and then we'll say comment we're going to create a new table called comment and again the aggregate part is is you know really in the Java world right as far as a database goes in a relational database goes we still have a table for comments um and this is going to include things like name so vodkar so this is going to be a hundred not at all we would have something like the content could be a whole bunch of text we're going to have that published let's just do this this is pretty much the same as that and so we'll do that so now the question really becomes okay if this doesn't have an ID what does it have well if you go through the documentation for spring data jwc you'll see that in this type of relationship we're going to have a column as the name of the aggregate root in this case it's going to be post and so that is an integer we obviously don't want that to be null what we'll also do here is just set up a foreign key which will go the post and that references the post ID so that's how we model the relationship here in the database schema so now that all looks good what we need to do is go back to post so let's go ahead and fill this in So at the end of the day a post is going to have a some type of collection of comments in our case this can be a set because we will have no duplicate comments and we can go ahead and say these are of type comment we'll call this comments and that will see actually let's go ahead and say new hash set we'll initialize that and that will give us that all right let's go ahead and we're going to add a getter and a Setter for those comments so Setter we actually didn't add one for our author so let's go ahead and set those and now I need a way to add comments so what I'm going to do is create a new method in here we will go ahead and say public void add comment and this is going to take in a comment and all we're going to do is we're going to say comments dot add and then we add in that comment now there's one more trick to this not really a trick but what we want to do is we've we've we have this post and we have all the comments that belong to this post but now we need to set a reference on the other side of this relationship right so how can we do that in the comment we can actually just set a reference to it now the trick here is we actually want to mark this with that transient because what we're saying is don't persist this off to the database this is really just a reference so now back in post what I can do is I can say the comment dot post is equal to this so now we've set a back reference to it so with that in place we should have everything we need to go ahead and add some comments to our posts that we created here so let's go ahead and introduce a local variable here we'll call this post and then in here I want to create some new comments and the way that I do that is I just say post dot add comment and so now I just want to go ahead and pass in a new comment so I can say new comment and I can say what is it what was the Constructor looking like um so name and content so I'm going to say my name is Dan and the content is this is my first comment so that is passing in a new comment and then what we can do oh actually we want to I don't want to save this yet right so what I want to do is I want to just create a new post add the comment to it and now say post dot save and I want to save that post so remember what we're saying here is that posts and comments kind of belong together right we are saying that that post is the aggregate route so when we save a post anything that is associated with it will now get saved so because comment belongs to the aggregate root post that will go ahead and get persistent now so let's see if that will go ahead and work let's try and restart our application and we did get an error let's see what we got here uh null not allowed for column published on okay so we need some values for that let's go back to comment and what we want to do is we want to set this dot published on equal to local date time dot now let's try and start that again and okay so that looks good let's head back to the H2 Council and see if those values got inserted all right so I'm here I'm going to go ahead and look at comment if we go ahead and select from there we see our one comment the content the published on updated is null so you see the post is now that reference back to the post that was inserted so if we look at posts that should have an ID of one and now that is how we tie that comment to this post all right so we are moving right along here I think what I want to do is kind of tie this all together we're going to create a controller a request a rest controller that we can go ahead and hit and kind of see some of the data that we're going to get back and that will allow us to talk about one more thing that I want to cover today so let's go ahead and create a new package we'll call this controller inside of controller we'll create a new Java class and we'll call it this post controller we'll mark this with at rest controller and we'll say the request mapping is for slash API slash posts so I'm going to need a couple things in here I'm going to need a post repository we'll call this posts and I'm also going to need a uthor repository we'll call this authors so I'm going to go ahead and say add this as a Constructor parameter to our Constructor and then I want to go ahead and get have a get mapping so we'll say public iterable iterable of post and we'll say this is find all and we're going to use the posts repository and go ahead and find all so that should return that Dan not just call it okay so far so good let's go ahead and restart this application and see if we can hit that API all right so we're here at localhost 8080 I'll go to slash API slash posts and close so far so good we we have some data here so let's look at this one we have the ID coming through of the post we probably want to hide that in the return uh in the response so we'll talk about that we have a title content published on the updated on is null good the author that we have coming back is just an object with an ID because again that is that aggregate reference to author it's really just an ID we may want some more information about that author to display on a page somewhere right and then you can see we're getting that set of comments back so we have some comments and we get the name content published on and updated on so I think the only thing I want to fix there is how can I get the um well in this case I don't think I would care about it right so if I'm just listing all the posts maybe I would but I think this this matters more on like a post detail page right so let's take a look at this I want to go ahead and say get mapping what if I was trying to get a specific post so public post find by ID and that would take in a path variable and that would be an integer ID and that would return our post repository dot find by ID and pass in that ID so we would oops so that is actually going to return an optional so we're going to say or else no so let's see if that works let's go ahead and rerun that we're going to try and hit that API slash posts slash one so let's do that cool so same thing just got that single post but as I said we may want an instance where we want to get some details about that particular post so I'm going to change this up or actually let's talk about this let's talk about creating what we call data transfer object right so in this case I have a post and I have an author these are two separate Aggregates but in one response I may I may want to have them both right so let's go in here and model I'm going to create a new let's say package called dto and in here I'm going to create something called a post details and this is going to be a record so post details may just contain a post which is called post and an author which is called author so that will have everything that I need so let's go ahead and create another mapping here I'm going to say this is going to be so for slash details find by ID let's just call this get post details and so this is going to take in a similar thing and I'll take in the path variable for that post but what we're going to return is a little bit different all we're returning is a new post details and so we're passing in that post so where this is going to be the same as above find by ID so we get the oh sorry so this is post dot find by ID so ID dot or else no and then we need to pass in an author so how do we get the author well what we can do is we can we we can use the authors repository so authors dot we can find by that ID and the way that we're going to get that ID is from the post that we created so we actually want to probably get this so let's say that introduce a local variable called post go ahead and pass that in and then we'll say the post get author dot get ID that should give us exactly what we need to get so now what we're doing is we're passing in whoops so we want to change this so we want to return post details and that should give us what we want so now if we go ahead and refresh this now in a case where I need the posts with all the details I can say slash details and now instead of just getting that author ID I will go ahead and get an author object on there so now I can display say the first name last name email username whatever I need to display there so that really is again the biggest hurdle if you've used jpa before is understanding the relationships as I said earlier you have to manage two types of relationships one between Aggregates so between the post and the author and then one within the aggregate which is in our case posts and comments so once you kind of wrap your head around that stuff there's some other little nuances and challenges that you have to understand but for me it simplifies everything you know there is no like wondering what happened behind the scenes you can see the sequel right here in the console you can go ahead and turn on some debugging to get that out but you can see exactly what's going on and so I really appreciate some of the Simplicity of spring data jdbc and I now that I understand it a little bit better I'm going to be using it in more of my projects I'm excited to hear from all of you have you used spring Data jdbc before what are your initial thoughts on it are you using it in real world projects so again this was my kind of first dive into it I've used it in the past but just for simple stuff this was a really a good chance to understand some of these relationships so hey I hope you enjoyed this tutorial if you found some value in it do me a favor hit that Thumbs Up Hit That subscribe button and as always friends happy coding here we go [Music]
Info
Channel: Dan Vega
Views: 21,027
Rating: undefined out of 5
Keywords: dan vega, spring jdbc, spring jdbc tutorial, what is spring jdbc, how to use spring jdbc, learn spring spring jdbc, spring jdbc data source, spring framework tutorial, spring jdbc example, spring framework, java, spring boot, spring tutorial, spring mvc tutorial, spring framework in java, spring, spring basics tutorial
Id: l_T0nQNbFiM
Channel Id: undefined
Length: 41min 48sec (2508 seconds)
Published: Fri Oct 07 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.